2

I have to interface to some old code that is using nested arrays, hence I have to convert my nested Lists to nested arrays.

I thought to myself that such feature should be already implemented in some existing library. I searched on Google/StackOverflow but nothing surfaced. I have checked Apache Commons and Guava but I did not find equivalent feature.

Here's my code, my concern is this can be done in a more simple way. Any idea, suggestions, improvements are warmly welcomed.

@SuppressWarnings("rawtypes")
public static <E> Class getNestedListClass(List<List<E>> list){
    if (list == null) {
        return null;
    }

    for (final List<E> innerList: list) {
        if (innerList == null || innerList.isEmpty()) {
            continue;
        }
        return innerList.get(0).getClass();
    }
    return null;
}

@SuppressWarnings({ "unchecked", "rawtypes" })
public static <E> E[][] convertNestedList(List<List<E>> list){
    final Class<?> clazz = getNestedListClass(list);
    if (clazz == null) {
        return null;
    }
    final E[][] result = (E[][]) Array.newInstance(clazz, list.size(), 0);

    for (int i = 0; i < list.size(); i++) {    
        final List<E> innerList = list.get(i);
        if (innerList == null) {
            continue;
        }
        result[i] = innerList.toArray((E[]) Array.newInstance(clazz, innerList.size()));
    }
    return result;
}


@Test
public void testConvertNestedList() {
    final List<List<String>> list = new ArrayList<List<String>>();
    list.add(new ArrayList<String>());
    list.get(list.size() - 1).add("0.0");
    list.get(list.size() - 1).add("0.1");
    list.get(list.size() - 1).add("0.2");
    list.add(new ArrayList<String>());
    list.get(list.size() - 1).add("1.0");
    list.get(list.size() - 1).add("1.1");
    list.get(list.size() - 1).add("1.2");
    list.get(list.size() - 1).add("1.3");
    list.add(new ArrayList<String>());
    list.get(list.size() - 1).add("2.0");
    list.get(list.size() - 1).add("2.1");

    final String[][] array = convertNestedList(list);

    final String[][] expected = new String[][] { 
            { "0.0", "0.1", "0.2" }, 
            { "1.0", "1.1", "1.2", "1.3" },
            { "2.0", "2.1" } };
    assertArrayEquals(expected, array);

}

EDIT added some test cases:

@Test
public void testConvertNestedListCaseNull() throws NetLineMarketException {
    List<List<Object>> list = null;
    Object[][] array = ArrayUtils.convertNestedList(list);
    Object[][] expected = null;
    assertArrayEquals(expected, array);
}

@Test
public void testConvertNestedListCaseNullElement() throws NetLineMarketException {
    List<List<Object>> list = new ArrayList<List<Object>>();
    list.add(null);
    Object[][] array = ArrayUtils.convertNestedList(list);
    Object[][] expected = new Object[][] { null };
    assertArrayEquals(expected, array);
}

@Test
public void testConvertNestedListCaseNullElement2() throws NetLineMarketException {
    List<List<Object>> list = new ArrayList<List<Object>>();
    list.add(new ArrayList<Object>());
    list.get(0).add(null);
    Object[][] array = ArrayUtils.convertNestedList(list);
    Object[][] expected = new Object[][] { { null } };
    assertArrayEquals(expected, array);
}

@Test
public void testConvertNestedListCaseEmpty() throws NetLineMarketException {
    List<List<Object>> list = new ArrayList<List<Object>>();
    Object[][] array = ArrayUtils.convertNestedList(list);
    Object[][] expected = new Object[][] { };
    assertArrayEquals(expected, array);
}

@Test
public void testConvertNestedListCaseString() throws NetLineMarketException {
    final String string = "string";
    List<List<Object>> list = new ArrayList<List<Object>>();
    list.add(new ArrayList<Object>());
    list.get(0).add(string);
    Object[][] array = ArrayUtils.convertNestedList(list);
    Object[][] expected = new Object[][] { { string } };
    assertArrayEquals(expected, array);
}

@Test(expected=MyException.class)
public void testConvertNestedListCaseMix() throws NetLineMarketException {
    final String string = "string";
    List<List<Object>> list = new ArrayList<List<Object>>();
    list.add(new ArrayList<Object>());
    list.get(0).add(string);
    list.get(0).add(Boolean.TRUE);
    Object[][] array = ArrayUtils.convertNestedList(list);
}
2
  • 1
    I think you pretty much have what you need. I can't see much place to real optimization here. Commented May 29, 2012 at 6:33
  • Generics and arrays really can't be made to play well together, as you've found out. That's why e.g. Guava doesn't address this: because if you're working with generics, you're better off sticking with Lists than trying to deal with arrays. Commented May 29, 2012 at 6:52

1 Answer 1

1

There are some problems with your code. For example:

  • List<Object>(null) is converted to null instead of Object[] { null }
  • List<Object>("string") is converted to String[] { "string" } instead of Object[] { "string" }
  • List<Object>("string", Boolean.TRUE) produces a run-time error.

My suggestion:

public static <T> T[][] toArray(List<List<T>> list, Class<T> clazz) {
    if (list == null) {
        return null;
    }
    List<T[]> temp = new ArrayList<>();
    @SuppressWarnings("unchecked")
    T[] inner = (T[]) Array.newInstance(clazz, 0);
    for (List<T> sublist : list) {
        temp.add(sublist == null ? null : sublist.toArray(inner));
    }
    @SuppressWarnings("unchecked")
    T[][] outer = (T[][]) Array.newInstance(inner.getClass(), temp.size());
    return temp.toArray(outer);
}
Sign up to request clarification or add additional context in comments.

1 Comment

Well, thanks for pointing out corner cases, I have added some testcases accordingly

Your Answer

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.