3

I am trying to find how to create a tuple of lists from a list of tuples. for example

f(list<tuple<u,v>>) => tuple<list<u>,list<v>>

This use case does not appear to be accommodated well by the standard API. Other articles say to use reduce, but this does not work since it will only return the same type as the input type.

In .net I would use Enumerable.Aggregate to achieve this.

Is there a functional way to achieve this in java?

Matt
  • 873
  • 1
  • 9
  • 24

2 Answers2

4

Java12 will provide Collectors.teeing which allows to apply two collectors and then merge their results

Meanwhile, you can apply reduce

Tuple<List<U>,List<V>> tupleOfLists = listOfTuples
  .stream()
  .reduce(
    new Tuple<List<U>,List<V>>(new ArrayList<U>(), new ArrayList<V>()),
    (tupleOfLists, tuple) -> {
      tupleOfLists.left().add(tuple.left());          
      tupleOfLists.right().add(tuple.right());
      return tupleOfLists;
    },
    (tupleOfLists1, tupleOfLists2) -> {
      tupleOfLists1.left().addAll(tupleOfLists2.left());
      tupleOfLists1.right().addAll(tupleOfLists2.right());
      return  tupleOfLists1;
    }
  );
Alexander Pavlov
  • 2,264
  • 18
  • 25
  • This does not appear to work since the method `reduce` is defined as `T reduce(T identity, BinaryOperator accumulator);`. Which means that the lambda of `(tupleOfLists, tuple)` is not of type `(,List>, Tuple)`, it is `(Tuple, Tuple)` – Matt Apr 22 '19 at 02:14
  • Updated. It should use reduce with 3 parameters – Alexander Pavlov Apr 22 '19 at 02:20
  • This third is required in case you run parallel stream. If you know you will never run parallel then you can use `(tupleOfLists1, tupleOfLists2) -> tupleOfLists1` or even dummy `(t1,t2)->null` – Alexander Pavlov Apr 22 '19 at 02:22
  • I missed that overload. Thanks! – Matt Apr 22 '19 at 02:23
1

It seems you would need to use Java 12, to write something like:

listOfTuples.stream().collect(teeing(
  map(t -> t.u).collect(Collectors.toList()),
  map(t -> t.v).collect(Collectors.toList()), 
  (us, vs) -> new Tuple(us,vs)
 ));

Haven't done this myself - just found a similare example here: https://www.baeldung.com/java-8-collectors

moilejter
  • 958
  • 8
  • 9