1
\$\begingroup\$

I have to interface to some old code using nested arrays, so I have to convert my nested Lists to nested arrays. Any idea, suggestions, improvements are warmly welcomed.

public static <E> int getNestedListMaxSize(List<List<E>> list){
    int result = 0;
    if (list != null && list.size() > 0){
        for (List<E> innerList : list){
            result = Math.max(result, innerList == null ? 0 : innerList.size());
        }
    }
    return result;
}

@SuppressWarnings("rawtypes")
public static <E> Class getNestedListClass(List<List<E>> list){
    Class result = null;
    if (list != null && list.size() > 0){
        for (List<E> innerList : list){
            if (innerList != null && innerList.size() > 0){
                result = innerList.get(0).getClass();
                break;
            }
        }
    }
    return result;
}

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

        for(int i=0; i < list.size(); i++) {
            E[] element = null;
            if (list.get(i) != null){
                E[] dummy = (E[]) Array.newInstance(clazz, list.get(i).size());
                element = list.get(i).toArray(dummy);
            }
            result[i] = element;
        }           
    }
    return result;
}

public static void main(String[] args) {
    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");

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

    System.out.println(Arrays.deepToString(array));
}
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

I'd use guard clauses to check whether the list parameter is null or not. Furthermore, the list.size() > 0 check looks unnecessary in the first two methods, the result will be same if you omit it.

Anyway, are you sure that null is an acceptable parameter here? Wouldn't it better to throw an exception in this case?

public static <E> int getNestedListMaxSize(final List<List<E>> list) {
    if (list == null) {
        return 0;
    }
    int result = 0;
    for (final List<E> innerList: list) {
        if (innerList == null) {
            continue;
        }
        result = Math.max(result, innerList.size());
    }
    return result;
}

In the getNestedListClass I'd use guard clauses too and a return instead of the break.

@SuppressWarnings("rawtypes")
public static <E> Class getNestedListClass(final 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;
}

I think the return makes the code much easier to read and follow.

In the convertNestedList method

  1. the dummy variable should have a meaningful name, for example innerListArray,

  2. the default value of result[i] is null, so you don't have to set it to null explicitly if the inner list is null,

  3. list.get(i) is called three times. It could have a local variable.

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

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

The main method should be a unit test method with proper assert calls:

@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 = ListConvert.convertNestedList(list);

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

It helps detecting regressions.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ I was worried I made some conceptual error, like there was a much simpler way to achieve my goal. Nevertheless, these are all valid and good remarks, so thanks @palacsint. \$\endgroup\$
    – bpgergo
    May 28, 2012 at 15:07
  • \$\begingroup\$ An idea: have you searched for already existed libraries which does this? \$\endgroup\$
    – palacsint
    May 28, 2012 at 15:28
  • 1
    \$\begingroup\$ Well, I searched on Google/StackOverflow and nothing surfaced. I also thought to myself that such feature should be already implemented in some existing library. I have checked Apache Commons and Guava but I did not find it. \$\endgroup\$
    – bpgergo
    May 28, 2012 at 15:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.