Multidimensional arrays and arrays of arrays

P

Philipp

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
 
J

Joshua Cranmer

Philipp said:
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.

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)....
 
R

RedGrittyBrick

Philipp said:
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];

You cant new a primitive type. I'll assume Float everywhere you wrote float.
Object b = new float[1][12];

if(a instanceof float[][]){

This is a compile time error (in Eclipse at least) - a [] isn't a [][]!

Did you intend to write "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.


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
 
P

Philipp

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

You cant new a primitive type. I'll assume Float everywhere you wrote float.

Nope. I new an array of primitive type, not a primitive type . (and
that example works on my machine)
  Object b = new float[1][12];
  if(a instanceof float[][]){

This is a compile time error (in Eclipse at least) - a [] isn't a [][]!

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

No, and that compiles OK here.
    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.

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

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
 
P

Philipp

Philipp said:
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.

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)....

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
 
S

Sigfried

Philipp a écrit :
Philipp said:
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.
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)....

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.

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.
 
J

Joshua Cranmer

Philipp said:
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.

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?
 
M

Mark Space

Patricia said:
public static boolean isArrayOfArrays(Object x){
Class<? extends Object> xClass = x.getClass();

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;
}
}
 
M

Mark Space

Patricia said:
...

You are right. I was being lazy. I'd started out with "Class<Object>",
got a compiler error, and accepted the first alternative Eclipse
suggested, rather than thinking through the simplest valid declaration.

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. ;)
 
D

Daniel Pitts

Philipp said:
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

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.
 
A

Arne Vajhøj

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.

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

Depending on ones definition of multidimensional array.

Arne
 
P

Philipp

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

Depending on ones definition of multidimensional array.

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[][]"
}
}
}
 
P

Philipp

Philipp said:
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?

Use the Class object's query methods, rather than extracting the name
and parsing it:

   /**
    * Test for array-of-arrays
    * @param x Non-null reference to an object.
    * @return true if, and only if, x is a reference to an
    * array of arrays.
    */
   public static boolean isArrayOfArrays(Object x){
     Class<? extends Object> xClass = x.getClass();
     if(! xClass.isArray()){
       return  false;
     }else{
       return xClass.getComponentType().isArray();
     }
   }

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
 
P

Philipp

The variable a references an array of Object references, one element of
which happens to reference a float array. The variable b references an
array of references to float arrays, every non-null element of which
*must* reference a float array.

I totally agree.
If, like me, you consider multidimensional arrays to be different from
arrays of references to array, please show me one in Java.

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

Phil
 
P

Philipp

Philipp said:
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.

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.

Thank you for pointing that out. It is interesting to see in the
source code how they go about reaching all dimensions...
Phil
 
L

Lew

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

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.
 
A

Arne Vajhøj

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

Depending on ones definition of multidimensional array.

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[][]"
}
}
}

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
 

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. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,011
Latest member
AjaUqq1950

Latest Threads

Top