1

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.

3
  • 3
    I deleted my answer, you will learn more by reading the Stream tutorial docs.oracle.com/javase/tutorial/collections/streams. Your code doesn't compile. Commented Apr 17, 2016 at 14:34
  • 1
    Your method is named getParts(), not getparts(). And Stream as a toArray() method, as well as a flatMap() method.. Commented Apr 17, 2016 at 14:37
  • 2
    In order to stream the elements of an array, you must use Arrays.stream(myArray). Currently, your list is a list of arrays, not a list of elements from the arrays. Commented Apr 17, 2016 at 14:37

3 Answers 3

3

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();
Sign up to request clarification or add additional context in comments.

1 Comment

I recommend using Arrays.stream instead of Stream.of in this situation.
1

You want to use .flatMap() instead of a .map(); in the lambda just generate a new stream of the items in the array.

Comments

1

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;
    }
}

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.