Reputation: 646
I have list of 1D arrays wrapped in an object, I want to collect them in 1 single array using java-8 stream and collect.
Given class Item with an array of
class A{
int x;
}
class Item{
A[] parts=new A[];
public A[] getParts(){
return parts;
}
}
So if I have list l
List<Item> l=new ArrayList<>();
l.add(new Item());
l.add(new Item());
I need to collect the content in these two object in one single array of type A.
So if first Item has parts={1,2}
and 2nd Item parts={3,4}
the output should be somehow like
A[] out={1,2,3,4}
I tried to do
l.stream().map(Item::getParts).collect(Collectors.toList()).toArray(new A[n]);
but apperantly it has meany problems.
Upvotes: 1
Views: 2480
Reputation: 21975
Map each Item
to its A[]
array. Then when having a stream of A[]
just flat map it to get each A
of each array and make it one array at the end.
A[] array = l.stream().map(x -> x.getParts())
.flatMap(x -> Arrays.stream(x))
.toArray(A[]::new); // [1, 2, 3, 4]
However, if you only interested in the int
value, there is an extra step
int[] array = l.stream().map(x -> x.getParts())
.flatMap(x -> Arrays.stream(x))
.mapToInt(x -> x.getX())
.toArray();
Upvotes: 3
Reputation: 1116
Try following:
static void test() {
List<Item> l = new ArrayList<>();
l.add(new Item(1, 2,5));
l.add(new Item(3, 4,10));
System.out.println(l);
int totalNoOfParts = l.stream().mapToInt(item->item.getParts().length).reduce(0, Integer::sum);
A[] allParts = l.stream().map(item -> item.getParts()).collect(() -> new A[totalNoOfParts],
(c, e) -> System.arraycopy(e, 0, c, getNextPos(c), e.length),
(c1, c2) -> System.arraycopy(c2, 0, c1, getNextPos(c1), c2.length));
System.out.println(Arrays.asList(allParts));
}
static int getNextPos(A[] a) {
for (int i = 0; i < a.length; i++) {
if (a[i] == null)
return i;
}
throw new InvalidParameterException("Invalid index value");
}
I modified your Item class to have fixed length of array.
class Item {
A[] parts = new A[3];
Item(int... values) {
Objects.requireNonNull(values, "Argument Not Valid");
for (int i = 0; i < values.length; i++) {
parts[i] = new A();
parts[i].x = values[i];
}
}
public A[] getParts() {
return parts;
}
}
Upvotes: 1
Reputation: 16142
You want to use .flatMap()
instead of a .map()
; in the lambda just generate a new stream of the items in the array.
Upvotes: 1