Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Java8 Streams to create a list of objects from another two lists

I have the following Java6 and Java8 code:

List<ObjectType1> lst1 = // a list of ObjectType1 objects
List<ObjectType2> lst2 = // a list of ObjectType1 objects, same size of lst1

List<ObjectType3> lst3 = new ArrayLis<ObjectType3>(lst1.size());
for(int i=0; i < lst1.size(); i++){
  lst3.add(new ObjectType3(lst1.get(i).getAVal(), lst2.get(i).getAnotherVal()));
}

Is there any way in Java8 to handle the previous for in a more concise way using Lambda?

like image 700
mat_boy Avatar asked Apr 08 '14 09:04

mat_boy


People also ask

How do you combine two lists of objects?

One way to merge multiple lists is by using addAll() method of java. util. Collection class, which allows you to add the content of one List into another List. By using the addAll() method you can add contents from as many List as you want, it's the best way to combine multiple List.

How do I compare one List with another List in Java 8?

Java provides a method for comparing two Array List. The ArrayList. equals() is the method used for comparing two Array List. It compares the Array lists as, both Array lists should have the same size, and all corresponding pairs of elements in the two Array lists are equal.

How do you convert a list of objects into a Stream of objects?

Converting a list to stream is very simple. As List extends the Collection interface, we can use the Collection. stream() method that returns a sequential stream of elements in the list.


2 Answers

A Stream is tied to a given iterable/Collection so you can't really "iterate" two collections in parallel.

One workaround would be to create a stream of indexes but then it does not necessarily improve over the for loop. The stream version could look like:

List<ObjectType3> lst3 = IntStream.range(0, lst1.size())
         .mapToObj(i -> new ObjectType3(lst1.get(i).getAVal(), lst2.get(i).getAnotherVal()))
         .collect(toList());
like image 131
assylias Avatar answered Oct 13 '22 09:10

assylias


You could create a method that transforms two collections into a new collection, like this:

public <T, U, R> Collection<R> singleCollectionOf(final Collection<T> collectionA, final Collection<U> collectionB, final Supplier<Collection<R>> supplier, final BiFunction<T, U, R> mapper) {
    if (Objects.requireNonNull(collectionA).size() != Objects.requireNonNull(collectionB).size()) {
        throw new IllegalArgumentException();
    }
    Objects.requireNonNull(supplier);
    Objects.requireNonNull(mapper);
    Iterator<T> iteratorA = collectionA.iterator();
    Iterator<U> iteratorB = collectionB.iterator();
    Collection<R> returnCollection = supplier.get();
    while (iteratorA.hasNext() && iteratorB.hasNext()) {
        returnCollection.add(mapper.apply(iteratorA.next(), iteratorB.next()));
    }
    return returnCollection;
}

The important part here is that it will map the obtained iteratorA.next() and iteratorB.next() into a new object.

It is called like this:

List<Integer> list1 = IntStream.range(0, 10).boxed().collect(Collectors.toList());
List<Integer> list2 = IntStream.range(0, 10).map(n -> n * n + 1).boxed().collect(Collectors.toList());
singleCollectionOf(list1, list2, ArrayList::new, Pair::new).stream().forEach(System.out::println);

In your example it would be:

List<ObjectType3> lst3 = singleCollectionOf(lst1, lst2, ArrayList::new, ObjectType3::new);

Where for example Pair::new is a shorthand for the lamdda (t, u) -> new Pair(t, u).

like image 33
skiwi Avatar answered Oct 13 '22 08:10

skiwi