Mohamed Gad-Elrab
Mohamed Gad-Elrab

Reputation: 646

Concatenate list of Objects arrays in Java8

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

Answers (3)

Yassin Hajaj
Yassin Hajaj

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

Chota Bheem
Chota Bheem

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

Tassos Bassoukos
Tassos Bassoukos

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

Related Questions