Let's say I have 4 Lists of equal size (N):
A = [22, -1, -10]
B = [3, -2, 54]
C = [-12, 3, 2]
D = [40, 4, -3]
I would like to combine them into another list of size N, by picking one number from each list at every index, based on a condition. Let's say we take the smallest positive integer, to keep in simple.
The result would look like this:
Result = [3, 3, 2]
What would be the most elegant way to do this using the Java streams API?
CodePudding user response:
I am confused by your example result because it does not match your question.
You said result should be size N = 4, but your example is size 3. You said build Result by picking one number from each list, then you picked 2 numbers from list C (3, 2).
I have given two solutions since I do not know which one you want.
public static void main(String[]args) {
List<Integer> A = Arrays.asList(22, -1, -10);
List<Integer> B = Arrays.asList(3, -2, 54);
List<Integer> C = Arrays.asList(-12, 3, 2);
List<Integer> D = Arrays.asList(40, 4, -3);
List<List<Integer>> listOfLists = Arrays.asList(A, B, C ,D);
// get the min positive integers by picking one from each lsit
List<Integer> positiveMinsPickOne = listOfLists.stream()
.map((list -> list.stream().filter(num -> num >= 0).min(Integer::compareTo).get()))
.collect(Collectors.toList());
System.out.println(positiveMinsPickOne);
// get the min positive integers by picking over all integers
List<Integer> positiveMinsPickAll = listOfLists.stream()
.flatMap(List::stream)
.filter(num -> num > 0)
.sorted()
.limit(listOfLists.size())
.collect(Collectors.toList());
System.out.println(positiveMinsPickAll);
}
Output:
[22, 3, 2, 4]
[2, 3, 3, 4]
CodePudding user response:
If this is a one-off, you can stream over the indexes and reduce them like this:
IntStream.range(0, a.size())
.mapToInt(col -> Stream.of(a, b, c, d)
.mapToInt(list -> list.get(col))
.filter(i -> i > 0)
.min()
.orElse(0))
.toArray()
If you need an abstraction for different type of reduction, you can create a method that handles the outer iteration and accepts a function to reduce each column:
int[] aggregate(List<List<Integer>> lists, ToIntFunction<IntStream> function) {
return IntStream.range(0, lists.get(0).size())
.mapToObj(col -> lists.stream().mapToInt(list -> list.get(col)))
.mapToInt(function)
.toArray();
}
You could call it like this to get the lowest positive value per column:
aggregate(Arrays.asList(a, b, c, d), col -> col.filter(i -> i > 0).min().orElse(0))