Search code examples
javajava-stream

How to map through a stream of Java pairs to consolidate into a single pair after some processing?


I have a Stream of pairs that I wish to map through and return them as a pair of strings, but not before doing something with them, first (I learned that teeing is a possible solution):

Stream<Pair<String, CustomObject>> stream = Stream.of(
  Pair.of("fruits",     Map.of("red","apple",   "yellow", "banana")),
  Pair.of("vegetables", Map.of("red","tomatoe", "yellow", "corn")),
  Pair.of("red meat",   Map.of("cow","beef",    "sheep", "mutton"))
  Pair.of("white meat", Map.of("fish","tuna",   "poultry", "chicken"))
);
Pair<String, String> result = stream.collect(Collectors.teeing(
  Collectors.?(this::parseFirstPair),
  Collectors.?(this::parseSecondPair),
  Pair::of
));
/*
result will be:
Pair<
  "(fruits, vegetables, red meat, white meat)",
  "Red apples, yellow bananas, red tomatoes, yellow corns, cow beef, sheep mutton, fish tuna, poultry chickens are all very nutritious for the human body!"
>
*/

I don't wish to group them, I don't wish to use a predicate.


Solution

  • If I understand correctly, this can indeed be done with teeing. The downstreams are just rather complicated compositions of other collectors.

    Pair<String, String> result = stream.collect(Collectors.teeing(
        Collectors.mapping(Pair::getFirst, Collectors.joining(", ", "(", ")")),
        Collectors.flatMapping(pair -> pair.getSecond().entrySet().stream(),
            Collectors.mapping(entry -> entry.getKey() + " " + entry.getValue(),
                Collectors.joining(", ", "", " are all very nutritious for the human body!"))),
        Pair::of
    ));
    

    result.getFirst() is:

    (fruits, vegetables, red meat, white meat)
    

    This is achieved by a mapping collector getting the first of each pair in the stream, and then using joining to make the result string, with ", " as the separator, "(" as the prefix, and ")" as the suffix.

    result.getSecond() is:

    red apple, yellow banana, red tomatoe, yellow corn, sheep mutton, cow beef, poultry chicken, fish tunaare all very nutritious for the human body!
    

    Since the second part of the pairs in the original stream is a map, and you want to process each entry, a flatMapping collector had to be used to map to the map entries. Then the entries are mapped to strings, and joined together like in the first downstream.