Multidimensional arrays and arrays of arrays

Discussion in 'Java' started by Philipp, Jan 15, 2009.

  1. Philipp

    Philipp Guest

    Hello
    How can I distinguish if an array is multidimensional of if it just
    contains an array? Or put it another way how can I tell at runtime
    whether a/b in the example below is an array containing an array, or
    if it is a multidimensional array.
    If I know beforehand exactly which type it is, I can use instanceof
    (see example), but I don't (especially the number of dimensions, I
    don't know).
    Else I can call getClass().getName() on the object and see if it
    starts with "[[" (pretty ugly IMHO).
    Is there another, cleaner method to do this?

    public static void main(String[] args) {
    Object[] a = new Object[1];
    a[0] = new float[12];

    Object b = new float[1][12];

    if(a instanceof float[][]){
    System.out.println("a is float[][]");
    }
    if(b instanceof float[][]){
    System.out.println("b is float[][]");
    }
    }

    prints "b is float[][]" (but not for a) as expected.

    Phil
     
    Philipp, Jan 15, 2009
    #1
    1. Advertisements

  2. Why do you want to distinguish? All arrays are subclasses of Object,
    which means an Object[] will capture all multidimensional arrays
    (although also regular Object arrays as well)....
     
    Joshua Cranmer, Jan 15, 2009
    #2
    1. Advertisements

  3. You cant new a primitive type. I'll assume Float everywhere you wrote float.
    This is a compile time error (in Eclipse at least) - a [] isn't a [][]!

    Did you intend to write "a instanceof Float[]" ?



    Since "a" can contain any type of object, wouldn't it be wrong for
    instanceof to report "a" as being of type Float[][]?

    Consider
    Object[] a = new Object[2];
    a[0] = new Float[12];
    a[1] = Color.RED;

    is a instanceof Float[]?
    is a instanceof Color[]?

    surely it is just instanceof Object[][]

    In these circumstances is it meaningfull to apply instanceof to anything
    other than a single element of a?

    a[0] instanceof Float is true
    a[1] instanceof Color is true
    a instanceof Object[] is true
     
    RedGrittyBrick, Jan 15, 2009
    #3
  4. Philipp

    Philipp Guest

    Nope. I new an array of primitive type, not a primitive type . (and
    that example works on my machine)
    No, and that compiles OK here.
    Yes evidently. I just wanted to make clear that you can't determine if
    an array is a multidimensional array, by checking if the first element
    of the array is an array itself.

    I have come up with some code which works pretty good for arrays of
    size different than 0 in all dimensions. Unfuortunately it fails when
    any dimension has length 0.

    public static int getNumberOfDimension(Object[] src){
    int dim = 1;
    if (src instanceof Object[][]) {
    // using recursion to reach all dimensions
    if(src.length > 0)
    dim += getNumberOfDimension((Object[])src[0]);
    }
    // handling primitive types explicitly
    else if(src instanceof boolean[][] ||
    src instanceof byte[][] ||
    src instanceof short[][] ||
    src instanceof int[][] ||
    src instanceof long[][] ||
    src instanceof float[][] ||
    src instanceof double[][]){
    dim = 2;
    }
    return dim;
    }

    Phil
     
    Philipp, Jan 15, 2009
    #4
  5. Philipp

    Philipp Guest

    For example I would like to write a method which gets an Object[] and
    prints out every element in it. If it is a multidimensional array, I
    would like it to iterate over all dimensions, and print only the
    leafs.

    Phil
     
    Philipp, Jan 15, 2009
    #5
  6. Philipp

    Sigfried Guest

    Philipp a écrit :
    To access the second dimension data, the first dimension must have at
    least 1 element, so you can use your hack wich needs > 0 length arrays.
     
    Sigfried, Jan 15, 2009
    #6
  7. Philipp

    Stefan Ram Guest

    It is just an array containing an array.
     
    Stefan Ram, Jan 15, 2009
    #7
  8. There is a method in java.util.Arrays (deepToString) which will return a
    string of the form "[foo, bar, [4, ..., a]]" that iterates over
    multidimensional arrays, with the added benefit that it can detect an
    array which contains itself.

    Would this be sufficient?
     
    Joshua Cranmer, Jan 15, 2009
    #8
  9. Philipp

    Mark Space Guest

    Isn't "extends Object" redundant? The upper bound of all wildcards is
    always Object.

    I just happened to be writing some code similar to what the OP is asking
    about. I was playing around with "Java lamda functions" and wanted to
    see if I could make a method take any type of array, Collection, or Map.
    The following code is presented without further comment, just as an
    example to inspire thought.

    /*
    * To change this template, choose Tools | Templates
    * and open the template in the editor.
    */
    package evaluator;

    import java.io.Serializable;
    import java.lang.reflect.Array;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.Collection;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Set;

    public class Eval1
    {
    /**
    * @param args the command line arguments
    */
    public static void main( String[] args ) throws LamdaException
    {
    Evaluater<Double> evalPlus3 = new Evaluater<Double>()
    {
    @Override
    public Double eval( Double o )
    {
    return o + 3.0;
    }
    };
    Evaluater<Object> evalPrintln = new Evaluater<Object>()
    {
    @Override
    public Void eval( Object o ) {
    System.out.println( o );
    return null;
    }
    };
    EvaluaterTransform<Double,String> evalFmt = new
    EvaluaterTransform<Double,String>() {
    @Override
    public String eval( Double d ) {
    return String.format( "%06.2g", d );
    }
    };

    EvaluaterAggregation<Double,String> fmtString =
    new EvaluaterAggregation<Double,String>() {

    StringBuilder sb = new StringBuilder();

    public void eval( Double o )
    {
    sb.append( String.format( "%06.2g", o));
    }

    public String getResult()
    {
    return sb.toString();
    }

    };

    double[] dArray = {1.2, 2.3, 3.4};
    ArrayList<Double> dAL = new ArrayList<Double>();
    dAL.add( 4.5 );
    dAL.add( 5.6 );
    HashMap<String, Double> sdHM = new HashMap<String, Double>();
    sdHM.put( "one", 6.7 );
    sdHM.put( "two", 7.8 );
    System.out.println( Arrays.toString( (double[]) lamda( dArray,
    evalPlus3 ) ) );
    System.out.println( lamda( dAL, evalPlus3 ) );
    System.out.println( lamda( sdHM, evalPlus3 ) );
    lamda( lamda(dArray, evalPlus3), evalPrintln );
    lamda( lamda(dArray, evalFmt), evalPrintln );
    // TODO car, cdr
    // lamdaFirst, lamdaSkipFirst ?
    // new class LamdaList which supports cdr car functions?
    }

    public static Object lamda( Object array, EvaluaterTransform ev )
    throws
    LamdaException
    {
    if( !array.getClass().isArray() &&
    !array.getClass().getComponentType().
    isPrimitive() ) {
    throw new LamdaException( "Object must be primitive array,
    was " +
    array.getClass().getName() );
    }
    Object retValue = Array.newInstance( Object.class, Array.getLength(
    array ) );
    if( int.class == array.getClass().getComponentType() ) {
    for( int i = 0; i < Array.getLength( array ); i++ ) {
    Array.set( retValue, i, ev.eval( Array.getInt( array, i
    ) ) );
    }
    } else if( double.class == array.getClass().getComponentType() ) {
    for( int i = 0; i < Array.getLength( array ); i++ ) {
    Array.set( retValue, i, ev.eval( Array.getDouble(
    array, i ) ) );
    }
    }
    return retValue;
    }

    public static Object lamda( Object o, Evaluater ev ) throws
    LamdaException
    {
    Object retval = null;
    if( o.getClass().isArray() ) {
    Class<?> arrayElementClass = o.getClass().getComponentType();
    Object newArray = Array.newInstance( arrayElementClass, Array.
    getLength( o ) );
    if( !arrayElementClass.isPrimitive() ) {
    for( int i = 0; i < Array.getLength( o ); i++ ) {
    Array.set( newArray, i, ev.eval( Array.get( o, i ) ) );
    }
    }
    else if( double.class == arrayElementClass ) {
    for( int i = 0; i < Array.getLength( o ); i++ ) {
    Object result = ev.eval( Array.getDouble( o, i ) );
    if( result != null ) {
    Array.setDouble( newArray, i, (Double) ev.eval(
    Array.
    getDouble( o, i ) ) );
    } else
    {
    Array.setDouble( newArray, i, 0.0 );
    }
    }
    }
    else if( int.class == arrayElementClass ) {
    for( int i = 0; i < Array.getLength( o ); i++ ) {
    Array.setInt( newArray, i, (Integer) ev.eval(
    Array.getInt( o, i ) ) );
    }
    }
    retval = newArray;
    }
    else if( o instanceof Collection ) {
    Collection<?> input = (Collection<?>) o;
    try {
    Collection<Object> newCollection =
    (Collection<Object>) o.getClass().newInstance();
    for( Object value : input ) {
    newCollection.add( ev.eval( value ) );
    }
    retval = newCollection;
    }
    catch( InstantiationException ex ) {
    // Logger.getLogger( Evaluator.class.getName() ).
    // log( Level.SEVERE, null, ex );
    throw new LamdaCollectionInstanteationException( "class=" +
    o.getClass().getName(), ex );
    }
    catch( IllegalAccessException ex ) {
    // Logger.getLogger( Evaluator.class.getName() ).
    // log( Level.SEVERE, null, ex );
    throw new LamdaCollectionInstanteationException( "class=" +
    o.getClass().getName(), ex );
    }
    }
    else if( o instanceof Map ) {
    Map input = (Map) o;
    try {
    Map newMap = input.getClass().newInstance();
    Set<Map.Entry> keySet = input.entrySet();
    for( Map.Entry key : keySet ) {
    Object result = ev.eval( key.getValue() );
    newMap.put( key.getKey(), result );
    }
    retval = newMap;
    }
    catch( InstantiationException ex ) {
    // Logger.getLogger( Evaluator.class.getName() ).
    // log( Level.SEVERE, null, ex );
    throw new LamdaMapInstanteationException( "class=" +
    o.getClass().getName(), ex );
    }
    catch( IllegalAccessException ex ) {
    // Logger.getLogger( Evaluator.class.getName() ).
    // log( Level.SEVERE, null, ex );
    throw new LamdaMapInstanteationException( "class=" +
    o.getClass().getName(), ex );
    }

    }

    return retval;
    }
    }

    interface Evaluater<T>
    {
    public T eval( T o );
    // public Class<T> getType();
    }

    interface EvaluaterAggregation<T,U>
    {
    public void eval( T o );
    public U getResult();
    // public Class<T> getEvalType();
    // public Class<U> getResultType();
    }

    interface EvaluaterTransform<T,U>
    {
    public U eval( T t );
    // public Class<T> getEvalType();
    // public Class<U> getReturnType();
    }

    class LamdaException extends Exception
    {
    public LamdaException( Throwable cause )
    {
    super( cause );
    }

    public LamdaException( String message, Throwable cause )
    {
    super( message, cause );
    }

    public LamdaException( String message )
    {
    super( message );
    }

    public LamdaException()
    {
    }
    }

    class LamdaMapInstanteationException extends LamdaException
    {
    public LamdaMapInstanteationException()
    {
    }

    public LamdaMapInstanteationException( String message )
    {
    super( message );
    }

    public LamdaMapInstanteationException( String message, Throwable
    cause )
    {
    super( message, cause );
    }

    public LamdaMapInstanteationException( Throwable cause )
    {
    super( cause );
    }
    }

    class LamdaCollectionInstanteationException extends LamdaException
    {
    public LamdaCollectionInstanteationException()
    {
    }

    public LamdaCollectionInstanteationException( String message )
    {
    super( message );
    }

    public LamdaCollectionInstanteationException( String message,
    Throwable cause )
    {
    super( message, cause );
    }

    public LamdaCollectionInstanteationException( Throwable cause )
    {
    super( cause );
    }
    }


    abstract class LamdaList implements Cloneable, Serializable
    {

    public LamdaListObject newLamdaList( Object [] o )
    {
    return new LamdaListObject( o );
    }

    public abstract LamdaList lamda( Evaluater e );
    public abstract double [] asDoubleArray();
    public abstract int [] asIntArray();
    public abstract LamdaList first();
    public abstract void first( Evaluater e );
    public abstract LamdaList skipFirst();
    public abstract void skipFirst( Evaluater e );
    public abstract boolean isPrimitive();
    public abstract boolean isPrimitiveDouble();
    public abstract boolean isPrimitiveInt();
    @Override
    public abstract String toString();
    @Override
    public abstract Object clone();
    }

    //class LamdaListObject extends LamdaList
    class LamdaListObject
    {
    Object [] oArray;

    LamdaListObject( Object[] o ){
    oArray = o;
    }
    }
     
    Mark Space, Jan 15, 2009
    #9
  10. Philipp

    Mark Space Guest

    I've decided to study for the SCJP exam so I have all sorts of language
    trivia stored in my head right now. Usually I program the same way as
    you -- whatever my IDE tells me is correct. ;)
     
    Mark Space, Jan 15, 2009
    #10
  11. Philipp

    Daniel Pitts Guest

    There is no difference between a multidimensional array, and an array of
    arrays. They are the same thing. Java provides a little syntactic sugar
    for allocation a uniform array of arrays (of arrays etc...), but there
    is no other difference, and no way to tell, other than testing each
    element of every array of arrays.
     
    Daniel Pitts, Jan 15, 2009
    #11
  12. Philipp

    Arne Vajhøj Guest

    You can do new float[12] just fine.

    Arne
     
    Arne Vajhøj, Jan 16, 2009
    #12
  13. Philipp

    Arne Vajhøj Guest

    Or we can say that Java does not have multidimensional arrays.

    Depending on ones definition of multidimensional array.

    Arne
     
    Arne Vajhøj, Jan 16, 2009
    #13
  14. Philipp

    Philipp Guest

    That's what I also thought at first.
    But my first example precisely showing that there _is_ a difference
    between an multidimensional array and an array of arrays, they are not
    of the same class type. The same code again, ready to compile and
    which emphasizes that classes of the two objects a and b anre not the
    same.

    public class ATest {
    public static void main(String[] args) {
    Object[] a = new Object[1];
    a[0] = new float[12];

    Object b = new float[1][12];

    System.out.println(a.getClass()); // prints "class
    [Ljava.lang.Object;"
    System.out.println(b.getClass()); // prints "class [[F"

    if(a instanceof float[][]){
    System.out.println("a is float[][]"); // does not print anything
    }
    if(b instanceof float[][]){
    System.out.println("b is float[][]"); // prints "b is float[][]"
    }
    }
    }
     
    Philipp, Jan 16, 2009
    #14
  15. Philipp

    Philipp Guest

    Excellent, that's pretty much what I was looking for. Thank you for
    your answer.

    Is there also a method to clone all dimensions of an array at once?

    Phil
     
    Philipp, Jan 16, 2009
    #15
  16. Philipp

    Philipp Guest

    I totally agree.
    I don't understand that question (if it is one).

    Phil
     
    Philipp, Jan 16, 2009
    #16
  17. Philipp

    Philipp Guest

    Thank you for pointing that out. It is interesting to see in the
    source code how they go about reaching all dimensions...
    Phil
     
    Philipp, Jan 16, 2009
    #17
  18. Quite right. I somehow read it as "a[0] = new float(12)".
     
    RedGrittyBrick, Jan 16, 2009
    #18
  19. Philipp

    Lew Guest

    It's a request, not a question. She is asserting that she considers
    multidimensional arrays to be different from arrays of references to array.
    If you agree that they are different, she requests that you show her an
    example of a multidimensional array in Java. That means that she asks you to
    illustrate a Java multidimensional array that is not an array of references to
    array.
     
    Lew, Jan 17, 2009
    #19
  20. Philipp

    Arne Vajhøj Guest

    Wrong tests.

    public class TwoDim {
    public static void main(String[] args) {
    float[][] a = new float[3][3];
    float[][] b = new float[3][];
    b[0] = new float[2];
    b[1] = new float[3];
    b[2] = new float[4];
    System.out.println(a.getClass().getName());
    System.out.println(b.getClass().getName());
    System.out.println(a instanceof float[][]);
    System.out.println(b instanceof float[][]);
    }
    }

    outputs:

    [[F
    [[F
    true
    true

    float[][] a = new float[3][3];

    is not a true two dimensional array - it is a quick way
    to create an array of arrays when all the second level
    arrays have the same length.

    Arne
     
    Arne Vajhøj, Jan 20, 2009
    #20
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.