3
\$\begingroup\$

I was working through getting myself past the creation of a generic method, that converts a List<T> or List<List<T>>, to T[] or T[][] respectively. Well, let's just consider a maximum dimension of 2 for now.

List<T> to T[] is quite straight-forward:

public static <T> T[] listToArray(List<T> list, Class<T> clazz) {
 /**** Null Checks removed for brevity ****/
 T[] arr = (T[]) Array.newInstance(clazz, list.size());
 for (int i = 0; i < list.size(); ++i) {
 arr[i] = list.get(i);
 }
 return arr;
}

Now I can call this method as:

List<String> list = new ArrayList<>(Arrays.asList("rohit", "jain"));
String[] arr = listToArray(list, String.class);

List<List<T>> to T[][] is what gives problems:

Now, here's the problem. Consider the code:

public static <T> T[][] multiListToArray(List<List<T>> listOfList, Class<T> clazz) {
 // Here I don't know what size to give for 2<sup>nd</sup> dimension
 // T[][] arr = (T[][]) Array.newInstance(clazz, listOfList.size(), ?);
 // So, I tried this. But this of course is not type safe
 // T[][] arr = (T[][]) new Object[listOfList.size()][];
 /* Only alternative I had was to iterate over the listOfList to get the
 maximum out of all the column sizes, which I can give as 2<sup>nd</sup>
 dimension later on. 
 */
 int maxCol = 0;
 for (List<T> row: listOfList) {
 if (row.size() > maxCol) {
 maxCol = row.size();
 }
 }
 // Now I can pass `maxCol` as 2<sup>nd</sup> dimension
 T[][] arr = (T[][]) Array.newInstance(clazz, listOfList.size(), maxCol);
 for (int i = 0; i < listOfList.size(); ++i) {
 List<T> row = listOfList.get(i);
 arr[i] = listOfList.get(i).toArray((T[])Array.newInstance(clazz, row.size()));
 }
 return arr;
}

Now, this is what I want to avoid - double iteration of List<List<T>> to be able to create the array. Is there any possibility?

asked Aug 12, 2013 at 21:45
\$\endgroup\$

3 Answers 3

4
\$\begingroup\$

Since you are creating new instance of arrays in your second loop, you don't need to know the size of the "inner list". Your "outer array" has to be as big as the "outer list". In a second phase, you instanciate the "inner arrays".

There's a simple way do this:

public <T> T[][] multiListToArray(final List<List<T>> listOfList, final Class<T> classz) {
 final T[][] array = (T[][]) Array.newInstance(classz, listOfList.size(), 0);
 for (int i = 0; i < listOfList.size(); i++) {
 array[i] = listOfList.get(i).toArray((T[]) Array.newInstance(classz, listOfList.get(i).size()));
 }
 return array;
}

More over, as you can see in the code above, you can provide a 0-length array to toArray(T[]) method.

This piece of code:

final List<List<String>> test = new ArrayList<List<String>>();
test.add(new ArrayList<String>(Arrays.asList("a", "b", "c")));
test.add(new ArrayList<String>(Arrays.asList("d", "e", "f", "g")));
test.add(new ArrayList<String>(Arrays.asList("h", "i")));
for (final String[] innerArray : multiListToArray(test, String.class)) {
 System.out.println(Arrays.toString(innerArray));
}

Will produce this output:

[a, b, c]
[d, e, f, g]
[h, i]

EDIT: There is an Ideone example.

EDIT 2: Code and Ideone updated to comply with OP needs.

answered Aug 13, 2013 at 12:20
\$\endgroup\$
2
  • \$\begingroup\$ Ah! Thanks for the 1st part. Yeah, I missed that point, that I can give 0 size for column initially. And regarding giving 0 size for array inside for loop, I would prefer to pass the size of the list, so that array don't need to be re-created in the method. Anyways thanks for your answer. :) \$\endgroup\$ Commented Aug 13, 2013 at 13:35
  • \$\begingroup\$ So you could replace array[i] = listOfList.get(i).toArray((T[]) Array.newInstance(classz, 0)); with array[i] = listOfList.get(i).toArray((T[]) Array.newInstance(classz, listOfList.get(i).size())); ;) \$\endgroup\$ Commented Aug 13, 2013 at 13:52
3
\$\begingroup\$

you could always reuse your existing listToArrayMethod to solve your problem

public static <T> T[][] multiListToArray(List<List<T>> listOfList, Class<T> clazz) {
 //unsure if this line will work but it should
 Class<List<T>> listClass = (Class<List<T>>) listOfList.get(0).getClass();
 List<T>[] arrayOfLists = listToArray(listOfList, listClass);
 T[][] array = (T[][]) Array.newInstance(clazz, arrayOfLists.length);
 for (int i = 0; i < arrayOfLists.length; i++) {
 List<T> arrayOfList = arrayOfLists[i];
 array[i] = listToArray(arrayOfList, clazz);
 }
 return array;
}

basically this works because we just have a list of list so we convert that to an array of list then we convert each of those to an array and place those inside our new array.

answered Aug 16, 2013 at 17:28
\$\endgroup\$
0
\$\begingroup\$

"Is there any possibility?"

Seems to be the only possibility...

/// A generic method to convert a list of lists to a two dimensional array
//
<T> T[][] makeArray ( List<List<T>> list ) { int i = 0;
 T[][] makeArray = (T[][]) Array.newInstance(list.get(0).get(0).getClass(),list.size(),0);
 for( List<T> tt : list )
 makeArray[i++] = (T[]) tt.toArray();
 return makeArray;
}
answered Aug 16, 2013 at 10:24
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.