In Java I want to convert a nested List which contains at the deepest level a uniform type into an multidimensional array of that type. For example, ArrayList<ArrayList<ArrayList<ArrayList<String>>>> into String[][][][]. I've tried several things and I only can obtain an array of objects like Object[][][][]. For 'simple lists' it seems that Apache Commons Lang does the work but I cannot figure out for nested cases.
Update:
In order to obtain a multidimensional array of Object type I'm using a recursive function so I cannot set the key type using toArray() see excerpt:
// the argument of this function is a (nested) list
public static Object convert(Object object) {
Object[] result = null;
List list = (List) object;
if (list != null) {
Object type = getElementType(list);
if (type instanceof List) {
int size = list.size();
result = new Object[size];
for (int counter = 0; counter < size; counter++) {
Object element = list.get(counter);
result[counter] = (element != null) ? convert(element) : null;
}
} else {
result = list.toArray();
}
}
return result;
}
private static Object getElementType(List list) {
Object result = null;
for (Object element : list) {
if (element != null) {
result = element;
break;
}
}
return result;
}
To create any kind of non-Object array, you need to pass a type key to the toArray method. This is because for generic types (e.g., ArrayList), the type argument is erased (so, at runtime, ArrayList<String> is treated as a plain ArrayList), whereas for arrays, the type is not.
It seems you already have the Object array creation sorted, so with that and the use of the type key, I think you're all sorted! :-)
This is the way that someone suggested to solved for String type. Cast2(List<?>) returns the multidimensional array. It may be generalized to use the class type as parameter. Thank you for your comments.
static int dimension2(Object object) {
int result = 0;
if (object instanceof List<?>) {
result++;
List<?> list = (List<?>) object;
for (Object element : list) {
if (element != null) {
result += dimension2(element);
break;
}
}
}
return result;
}
static Object cast2(List<?> l) {
int dim = dimension2(l);
if (dim == 1) {
return l.toArray(new String[0]);
}
int[] dims = new int[dimension2(l)];
dims[0] = l.size();
Object a = Array.newInstance(String.class, dims);
for (int i = 0; i < l.size(); i++) {
List<?> e = (List<?>) l.get(i);
if (e == null) {
Array.set(a, i, null);
} else if (dimension2(e) > 1) {
Array.set(a, i, cast2(e));
} else {
Array.set(a, i, e.toArray(new String[0]));
}
}
return a;
}
hehe, heres a answer too but i dunno if that really helps:
List<ArrayList<ArrayList<ArrayList<String>>>> x = new ArrayList<ArrayList<ArrayList<ArrayList<String>>>>();
public static void main(String[] args) throws MalformedURLException, IOException, SecurityException, NoSuchFieldException {
Type t = ((ParameterizedType)(jdomTEst.class.getDeclaredField("x").getGenericType())).getActualTypeArguments()[0];
int[] dims = new int[t.toString().split("List").length];
Object finalArray = Array.newInstance(String.class, dims);
System.out.println(finalArray);
}
this prints: [[[[Ljava.lang.String;#4e82701e
looks pretty messy but i love reflections :)
You can use transmorph :
ArrayList<ArrayList<ArrayList<ArrayList<String>>>> arrayList = new ArrayList<ArrayList<ArrayList<ArrayList<String>>>>();
/// populate the list ...
[...]
Transmorph transmorph = new Transmorph(new DefaultConverters());
String[][][][] array = transmorph.convert(arrayList, String[][][][].class);
Related
I'm trying to write a Java function which takes a List of Lists holding objects of any class, and then calculates the size of the set consisting of all different combinations of inner list objects, where all objects come from different lists. The algorithm is simple:
int combos(List<List<Object>> inList) {
int res = 1;
for(List<Object> list : inList) {
res *= list.size();
}
return res;
}
But I'm getting this error when trying to run the function with a List<List<Integer>> object as input parameter:
List<List<Integer>> input = new ArrayList<List<Integer>>();
input.add(new ArrayList<Integer>());
input.get(0).add(1);
input.get(0).add(2);
combos(input);
The error:
The method combos(List<List<Object>>) in the type SpellChecker is not applicable for the arguments (List<List<Integer>>)
As far as I understand, Object is the parent class of Integer. So why doesn't this work? How can I make it work?
The relationship between Object and Integer does not apply to List<Object> and List<Integer>, see e.g. this related question for more details.
Use a type parameter:
<T> int combos(List<List<T>> inList) {
int res = 1;
for(List<T> list : inList) {
res *= list.size();
}
return res;
}
One solution is to use a type parameter in combos:
<T> int combos(List<List<T>> inList) {
int res = 1;
for(List<T> list : inList) {
res *= list.size();
}
return res;
}
This is closely related to this question about nested generics. The answer in that question provides some good info.
On top of the two good answers you already got here is another option.
public static void main(String[] args) {
List<List<Integer>> input = new ArrayList<>();
input.add(new ArrayList<>());
input.get(0).add(1);
input.get(0).add(2);
combos(input);
}
static int combos(List<? extends List<?>> inList) {
int res = 1;
for (List<?> list : inList) {
res *= list.size();
}
return res;
}
This also works, if you don't need to specialize the List Datatype as List<Integer>
List<List<Object>> input = new ArrayList<List<Object>>();
input.add( new ArrayList<Object>() );
input.get( 0 ).add( new Integer(1) );
input.get( 0 ).add( new Integer(2) );
combos( input );
Hi I'm very new to Java and in this code, I think I'm not creating the Bag correctly in the Main? Please help thanks!
Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Comparable;
at mid.Bag.(Bag.java:12)
at mid.Bag.main(Bag.java:91)
public class Bag<T extends Comparable<T>> implements Iterable<T> {
private int MAX_ITEMS = 10; // initial array size
private int size;
private T[] data;
public Bag( ) {
data = (T []) new Object[MAX_ITEMS];
size = 0;
}
public void add(T newItem) {
// check if it's full, then extend (array resizing)
if (size == data.length) {
T[ ] temp = (T [ ] ) new Object[data.length*2];
for (int i = 0; i < size; ++i)
temp[i] = data[i];
// reassign data to point to temp
data = temp;
}
// then do the assignment
data[size++] = newItem; // assign newItem in the next-available slot
}
public Iterator<T> iterator() {
return new BagIterator();
}
/***************************
* nested class BagIterator
***************************/
class BagIterator implements Iterator<T> {
// instance member
private int index;
// (0) constructor
public BagIterator() {
index = 0;
}
// (1)
public boolean hasNext() {
return (index < size); // size in the outer Bag<E>
}
// (2)
public T next() {
/*
T temp = data[index]; // save the element value
index++; // increment index
return temp;
*/
return data[index++];
}
public static void main(String[ ] args) {
Bag<String> bag1=new Bag<String>();
bag1.add("good");
bag1.add("fortune");
bag1.add("billionarie");
for (String x: bag1)
System.out.println(x);
}
Yes, you're creating an Object[] and then trying to cast it to T[], which the compiler is converting to a cast to Comparable[] (using the raw Comparable type) due to your constraint on T.
Arrays and generics don't work terribly nicely together, basically.
It would probably be simpler to make your data field just an Object[] and cast individual values where necessary.
Here:
data = (T []) new Object[MAX_ITEMS];
you are constructing an Object array and trying to cast it to T[]. But you have declared that T inherits from Comparable. So use:
data = (T []) new Comparable[MAX_ITEMS];
You can probably rewrite your constructor as well:
public Bag(Class<T> c, int s) {
// Use Array native method to create array of a type only known at run time
#SuppressWarnings("unchecked")
final T[] dataArray = (T[]) Array.newInstance(c, s);
this.data = dataArray;
}
Then you can use it like:
Bag<String> bag1 = new Bag<>(String.class,10);
That should also work, IMO. The instances of T must be comparable in any case.
I have array list like this
ArrayList list = new ArrayList();
list.add("somethingold");
list.add(3);
list.add("somethingnew");
list.add(5);
Now if I print the list output will be like:
[somethingold, 3, somethingnew, 5 ]
Here i want to fetch only integer elements.
I want the output like, if it is an integer put it in some other list, else in one more list.
This is what i want:
[3,5]
[somethingold, somethingnew]
have you tried this?:
if(list.get(0) instanceof Integer) {
// is an integer
} else if (list.get(0) instanceof String) {
// is a String
}
Looping through each element in List
for loop:
for (int i = 0; i < list.size(); i++) {
if (list.get(i) instanceof Integer) {
// do your stuff
}
if (list.get(i) instanceof String) {
// do your stuff
}
}
for-each loop:
for (Object obj: list) {
if (obj instanceof Integer) {
// do your stuff
}
...
}
You can achieve it using instanceof operator.
for (Object object : list)
{
if(object instanceof Integer)
{
System.out.println(object); // Integer
}
else if(object instanceof String)
{
System.out.println(object); // String
}
}
its very simple. Just two lines of code
string[] stringList = list.OfType<string>().ToArray();
Int32[] intList = list.OfType<Int32>().ToArray();
It is recommended that should create typed Collection like List<Integer> or List<String> if you are using java 1.5+.
In case of generic array you can use instanceOf operator to differentiate .
for(Object obj: list){
if(obj instanceOf Ineteger){
...
}else if(obj instanceOf String){
...
}
}
you are trying to go over the JDK API , that was one of the most important reason why Generics were introduced in java, to provide you type safe collections.
And you have no need to worry while adding or fetching the elements(no explicit typecasting required).
A friendly suggestion go by the book.
Thanks
You want [3,5] [somethingold, somethingnew] which looks already like 2 separate lists.
So you could do
class IntegersAndStrings {
private final List<String> strings = new ArrayList<String>();
private final List<Integer> ints = new ArrayList<Integer>();
public void add(int i) {
ints.add(Integer.valueOf(i));
}
public void add(String s) {
strings.add(s);
}
#Override
public String toString() {
return ints.toString() + strings.toString();
}
}
and use it like before
class Main {
public static void main(String[] args) {
IntegersAndStrings list = new IntegersAndStrings();
list.add("somethingold");
list.add(3);
list.add("somethingnew");
list.add(5);
System.out.println(list);
}
}
and the output would be
[3, 5][somethingold, somethingnew]
You have to fetch list of objects by using for-loop, in that you can find out string and integers.
Below example shows how to get the values..
ArrayList list = new ArrayList();
for (Object o : list) {
if (o.getClass().equals(Integer.TYPE)) {
...
}
else if (o.getClass().equals(String.class)) {
...
}
}
Collections.sort(list);
int index = 0;
for (Object obj: list) {
index ++;
if (obj instanceof String) {
break;
}
}
List<Integer> integerList = list.subList(0.index);
List<String> stringList = list.subList(index,list.size());
System.out.println(integerList);
System.out.println(stringList);
Try this, i hope it works
Using guava library you can do it like this:
System.out.println(
Iterators.toString(Iterators.filter(list.iterator(), String.class)));
System.out.println(
Iterators.toString(Iterators.filter(list.iterator(), Integer.class)));
TreeNode[] children = grid[row][col].getChildren();
I would like a simple function that can tell me how many objects are in this array? getChildren() will return an object of size no larger than 4, for example:
children[0] = null;
children[1] = TreeNode Object
children[2] = null;
children[3] = null;
Why don't you write it yourself:
public static <T> int getLength(T[] arr){
int count = 0;
for(T el : arr)
if (el != null)
++count;
return count;
}
Code:
Arrays.stream(list).filter(e -> e != null).count();
This should work. Essentially the same with the function written for you and not TreeNode specific.
int initLength(Object[] myArray) {
int count = 0;
for (Object obj : myArray) {
if ( obj != null ) count++;
}
return count;
}
I called it initLength because those items are init'd but call it what you like. Some would say it's init'd when you define it, regardless of whether the contents are null.
Other alternative:
ArrayList l = new ArrayList(Arrays.asList(children));
l.removeAll(Collections.singleton(null));
l.size();
Perhaps overkill to use predicates, but here's a Guava solution:
int numNotNull = Iterables.size( Iterables.filter( Arrays.asList( children ),
Predicates.notNull() ));
In Java 8, you can use Math.toIntExact and Arrays.stream to construct a nice one-liner:
Math.toIntExact(Arrays.stream(row).filter(s -> s != null).count())
I want a function / data structure that can do this:
func(int dim){
if(dim == 1)
int[] array;
else if (dim == 2)
int[][] array;
else if (dim == 3)
int[][][] array;
..
..
.
}
anyone know how?
Edit
Or you could use Array.newInstance(int.class, sizes). Where sizes is an int[] containing the desired sizes. It will work better because you could actually cast the result to an int[][][]...
Original Answer
You could use the fact that both int[] and Object[] are Objects. Given that you want a rectangular multidimensional array with sizes given by the list sizes
Object createIntArray(List<Integer> sizes) {
if(sizes.size() == 1) {
return new int[sizes.get(0)];
} else {
Object[] objArray = new Object[sizes.get(0)];
for(int i = 0; i < objArray.length; i++) {
objArray[i] = createIntArray(sizes.subList(1, sizes.size());
}
return objArray;
}
}
You lose all static type checking, but that will happen whenever you want a dynamically dimensioned array.
If your purpose is to create a truly dynamic array, then you should look at the Array object in the JDK. You can use that to dynamically generate an array of any dimension. Here is an example:
public void func(int dim) {
Object array = Array.newInstance(int.class, new int[dim]);
// do something with the array
}
Once the array Object has been created, you can use the methods of the java.lang.reflect.Array class to access, add, remove elements from the multi-dimension array that was created. In also includes utility methods to determine the length of the array instance.
You can even check the dimension of the array using:
public int getDimension(Object array) {
int dimension = 0;
Class cls = array.getClass();
while (cls.isArray()) {
dimension++;
cls = cls.getComponentType();
}
return dimension;
}
People have post good solutions already, but I thought it'd be cool (and good practice) if you wrap the dynamic multidimensional array into a class, which can use any data structure to represent the multi-dimensional array. I use hash table so you have virtually unlimited size dimensions.
public class MultiDimArray{
private int myDim;
private HashMap myArray;
public MultiDimArray(int dim){
//do param error checking
myDim = dim;
myArray= new HashMap();
}
public Object get(Integer... indexes){
if (indexes.length != myDim){throw new InvalidArgumentException();}
Object obj = myArray;
for (int i = 0; i < myDim; i++){
if(obj == null)
return null;
HashMap asMap = (HashMap)obj;
obj = asMap.get(indexes[i]);
}
return obj;
}
public void set(Object value, Integer... indexes){
if (indexes.length != myDim){throw new InvalidArgumentException();}
HashMap cur = myArray;
for (int i = 0; i < myDim - 1; i++){
HashMap temp = (HashMap)cur.get(indexes[i]);
if (temp == null){
HashMap newDim = new HashMap();
cur.put(indexes[i], newDim);
cur = newDim;
}else{
cur = temp;
}
}
cur.put(indexes[myDim -1], value);
}
}
and you can use the class like this:
Object myObj = new Object();
MultiDimArray array = new MultiDimArray(3);
array.put(myObj, 0, 1, 2);
array.get(0, 1, 2); //returns myObj
array.get(4, 5, 6); //returns null
What about a class like following?
class DynaArray {
private List<List> repository = new ArrayList<List>();
public DynaArray (int dim) {
for (int i = 0; i < dim; i++) {
repository.add(new ArrayList());
}
}
public List get(int i) {
return repository.get(i);
}
public void resize(int i) {
// resizing array code
}
}