2

Possible Duplicate:
Convert ArrayList into 2D array containing varying lengths of arrays

How can I convert a Collection<List<Foo>> into a 2D array of type Foo[][]?

I'm trying to use the toArray method, but I'm not sure about the syntax. For instance, this doesn't work:

import com.google.common.collect.Collections2;
Collection<List<Foo>> permuted = Collections2.permutations(bar);
Foo[][] permutedArray = permuted.toArray(new Foo[10][10]);//exception here

it's throwing ArrayStoreException. In this case, what should be the type for permutedArray?

Community
  • 1
  • 1
Chin
  • 19,717
  • 37
  • 107
  • 164

3 Answers3

3

.toArray can only convert the collection into a List<Foo>[]. You need to call .toArray on each element of the array of list again to really get a Foo[][].

    @SuppressWarnings("unchecked")
    final List<Foo>[] permutedList = permuted.toArray(new List[10]);
    final Foo[][] permutedArray = new Foo[10][10];
    for (int j = 0; j < 10; ++j) {
        permutedArray[j] = permutedList[j].toArray(new Foo[10]);
    }
Chin
  • 19,717
  • 37
  • 107
  • 164
kennytm
  • 510,854
  • 105
  • 1,084
  • 1,005
1

This seems like it might make more sense to do a set of nested loops:

//Untested, I might have made some silly mistake
T[][] array = new T[collection.size()[];
int collection = 0;
int list = 0;

for(List<T> list : collection)
{
  list = 0;
  array[collection] = new T[list.size()];
  for(T t : list)
    array[collection][list++] = t;

  collection++;
}

The "toArray" method is handy, but because of Generic types I usually find it frustrating to work with. Utility methods like this generally read easier and avoid the problems you're running into.

EDIT: I should note: you need to know or cast T. It will generate an unchecked types exception (which of course is unchecked!).

Daniel B. Chapman
  • 4,647
  • 32
  • 42
0

What if you try something like the following generic utility function:

public static <T> T[][] asMatrix(
    Collection<? extends Collection<? extends T>> source,
    T[][] target) {

    // Create a zero-sized array which we may need when converting a row.
    @SuppressWarnings("unchecked") T[] emptyRow =
        (T[])Array.newInstance(target.getClass().getComponentType().getComponentType(), 0);

    List<T[]> rows = new ArrayList<T[]>(source.size());
    int i = 0;
    for (Collection<? extends T> row : source) {
        T[] targetRow = i < target.length ? target[i] : null;
        rows.add(row.toArray(targetRow != null ? targetRow : emptyRow));
        i += 1;
    }
    return rows.toArray(target);
}

Usage:

Collection<List<Foo>> permuted = ...;
Foo[][] result = asMatrix(permuted, new Foo[][] {});

The way it works is to visit each sub collection (i.e., row), converting it into an array. We cache these arrays in a collection. We then ask that collection to convert itself into an array, which we use as the result of the function.

The benefits of this utility function are:

  1. It uses Collection.toArray for all of the array construction and copying.
  2. The function is generic and so can handle any kind of reference type (unfortunately native types like int, long, etc., will require more work).
  3. You pass in the target array, which might even be preallocated to a certain size, behaving exactly the same as Collection.toArray does.
  4. The function is tolerant of collections that change their size concurrently (as long as the collections are themselves tolerant).
  5. The conversion is type safe and type strict.

More examples:

List<List<Integer>> list =
    Arrays.asList(Arrays.asList(1, 2), Arrays.asList(3, 4));

Integer[][] result;

result = asMatrix(list, new Integer[][] {});
System.out.println(Arrays.deepToString(result));

result = asMatrix(list, new Integer[][] {new Integer[] {9, 9, 9, 9}, null});
System.out.println(Arrays.deepToString(result));

Result:

[[1, 2], [3, 4]]
[[1, 2, null, 9], [3, 4]]
cambecc
  • 4,083
  • 1
  • 23
  • 24