I am trying to Flatten a ArrayList with N-Depth. For this I tried using flapMap method of Stream API. I am able to get it. But I have to use flatMap() method repeatedly as per the number of list of lists. If I am using one more flatMap() method, it shows compile time error. Is there any way to dynamically get it done.
This is the code that I used:
List<Integer> list1 = Arrays.asList(4,5,6);
List<Integer> list2 = Arrays.asList(7,8,9);
List<List<Integer>> listOfLists = Arrays.asList(list1, list2);
List<List<List<Integer>>> listA = Arrays.asList(listOfLists);
List<List<List<List<Integer>>>> listB = Arrays.asList(listA);
List<Integer> listFinal = listB.stream()
.flatMap(x -> x.stream())
.flatMap(x -> x.stream())
.flatMap(x -> x.stream())
.collect(Collectors.toList());
//In the above line, If I use listA instead of listB, it is showing error.
listFinal.forEach(x-> System.out.println(x));
For List<List<List<List<Integer>>>> listB, .stream().flatMap(.stream()).flatMap(.stream()).flatMap(.stream()).collect()
But for List<List<List<Integer>>> listA, .stream().flatMap(.stream()).flatMap(.stream()).collect().
See flatMap() count is just one less than the Generic depth.
I hope you know that deeply nested collections isn't the best way to represent the data and must be avoided (it's an almost certain indicator of faulty design). So I'll treat this question as a cryptic puzzle rather than a practical task.
You can achieve that without using recursion. But caution this approach is vicious as well recursion because as well recursive approach it requires to relinquish the type safety provided by generics (I've warned that you shouldn't do that in the first place).
To do that, you need to perform intanceof checks in a loop. And populate the resulting list of row type with elements of a nested list.
Note :
List<Integer> which characterized as covariant (i.e. you can assign only collection of the same type to it) you're allowed and to assign anything to the list of row type and to modify it as well. Which is an unsafe combination, and hence usage of row type collections is highly discouraged.The loop exits if the first element isn't a list.
public static void main(String[] args) {
List<List<List<List<Integer>>>> source =
List.of(List.of(List.of(List.of(4,5,6), List.of(7,8,9))));
List<Integer> result = source.stream()
.flatMap(list -> deepFlatten(list).stream())
.collect(Collectors.toList());
System.out.println(source);
System.out.println(result);
}
public static List<Integer> deepFlatten(List<?> nestedList) {
if (nestedList.isEmpty()) {
return (List<Integer>) nestedList;
}
List result = new ArrayList<>();
List current = nestedList;
while (current.get(0) instanceof List<?>) {
for (Object next: current) {
result.addAll((List) next);
}
current = result;
result = new ArrayList<>();
}
return (List<Integer>) current;
}
Output
[[[[4, 5, 6], [7, 8, 9]]]]
[4, 5, 6, 7, 8, 9]