3

In previous question I asked previously Which FunctionalInterface should I use?

Now I was trying to add to List<Integer> and not just two Integers a and b, such that each index adds to the same index of another list.

I had previously

 BinaryOperator<Integer> binaryOperator = Integer::sum;

for adding two integers using binaryOperator.apply(int a,int b). Is there a similar way like

BinaryOperator<List<Integer>> binaryOperator = List<Integer>::sum;

and then get the result in List<Integer> cList?

Naman
  • 27,789
  • 26
  • 218
  • 353
Mani
  • 1,068
  • 3
  • 13
  • 27

3 Answers3

5

if you want to perform some computation on the elements at corresponding indices (in this specific case the summation) there's no need to use a BinaryOperator, instead use IntStream.range to generate the indices:

// generates numbers from 0 until list.size exclusive 
IntStream.range(0, list.size())....

// generates numbers from 0 until the minimum of the two lists exclusive if needed
IntStream.range(0, Math.min(list.size(), list2.size()))....

The common name for this type of logic is "zip"; i.e. when given two input sequences it produces an output sequence in which every two elements from the input sequences at the same position are combined using some function.

There's no built-in method in the standard library for this, but you can find some generic implementations here.

for example, using the zip method in the accepted answer of the linked post, you could simply do:

List<Integer> result = zip(f.stream(), s.stream(), (l, r) -> l + r).collect(toList());

or using method reference:

List<Integer> result = zip(f.stream(), s.stream(), Math::addExact).collect(toList());

where f and s are your list of integers.

Ousmane D.
  • 54,915
  • 8
  • 91
  • 126
1

You can use IntStream.range() to iterate over elements, then mapToObj() to map them to their sum and the collect() them in the third list.

Given that your lists are of same size

List<Integer> first = List.of(); // initialised
List<Integer> second = List.of(); // initialised

you can get the third list as :

List<Integer> third = IntStream.range(0, first.size())
                               .mapToObj(i -> first.get(i) + second.get(i))
                               .collect(Collectors.toList());

In terms of BinaryOperator, you can represent it as :

BinaryOperator<List<Integer>> listBinaryOperator = (a, b) -> IntStream.range(0, first.size())
            .mapToObj(i -> first.get(i) + second.get(i))
//          OR from your existing code
//          .mapToObj(i -> binaryOperator.apply(first.get(i), second.get(i)))
            .collect(Collectors.toList());

Or you can make it more readable by abstracting out the logic into a method and using it as :

BinaryOperator<List<Integer>> listBinaryOperator = YourClass::sumOfList;

where sumOfList is defined as :

private List<Integer> sumOfList(List<Integer> first, List<Integer> second) {
    return IntStream.range(0, first.size())
            .mapToObj(i -> first.get(i) + second.get(i))
            .collect(Collectors.toList());
}
Naman
  • 27,789
  • 26
  • 218
  • 353
1

What you can do is define your own utility method whose single task is zipping the two input lists :

<T> List<T> zip(final List<? extends T> first, final List<? extends T> second, final BinaryOperator<T> operation)
{
    return IntStream.range(0, Math.min(first.size(), second.size()))
        .mapToObj(index -> operation.apply(first.get(index), second.get(index)))
        .collect(Collectors.toList());
}

This way, you can sum your two input lists as :

zip(first, second, Integer::sum)
HPH
  • 388
  • 2
  • 11