Java 8 stream join and return multiple values

后端 未结 4 1414
时光说笑
时光说笑 2020-12-17 22:32

I\'m porting a piece of code from .NET to Java and stumbled upon a scenario where I want to use stream to map & reduce.

class Content
{
  private String          


        
4条回答
  •  悲哀的现实
    2020-12-17 22:41

    The most generic way to deal with such tasks would be to combine the result of multiple collectors into a single one.

    Using the jOOL library, you could have the following:

    Content content = 
        Seq.seq(contentList)
           .collect(
             Collectors.mapping(Content::getA, Collectors.joining(", ")),
             Collectors.mapping(Content::getB, Collectors.joining(", ")),
             Collectors.mapping(Content::getC, Collectors.joining(", "))
           ).map(Content::new);
    

    This creates a Seq from the input list and combines the 3 given collectors to create a Tuple3, which is simply a holder for 3 values. Those 3 values are then mapped into a Content using the constructor new Content(a, b, c). The collector themselves are simply mapping each Content into its a, b or c value and joining the results together separated with a ", ".


    Without third-party help, we could create our own combiner collector like this (this is based of StreamEx pairing collector, which does the same thing for 2 collectors). It takes 3 collectors as arguments and performs a finisher operation on the result of the 3 collected values.

    public interface TriFunction {
        R apply(T t, U u, V v);
    }
    
    public static  Collector combining(Collector c1, Collector c2, Collector c3, TriFunction finisher) {
    
        final class Box {
            A a; B b; C c;
            Box(A a, B b, C c) {
                this.a = a;
                this.b = b;
                this.c = c;
            }
        }
    
        EnumSet c = EnumSet.noneOf(Characteristics.class);
        c.addAll(c1.characteristics());
        c.retainAll(c2.characteristics());
        c.retainAll(c3.characteristics());
        c.remove(Characteristics.IDENTITY_FINISH);
    
        return Collector.of(
                () -> new Box<>(c1.supplier().get(), c2.supplier().get(), c3.supplier().get()),
                (acc, v) -> {
                    c1.accumulator().accept(acc.a, v);
                    c2.accumulator().accept(acc.b, v);
                    c3.accumulator().accept(acc.c, v);
                },
                (acc1, acc2) -> {
                    acc1.a = c1.combiner().apply(acc1.a, acc2.a);
                    acc1.b = c2.combiner().apply(acc1.b, acc2.b);
                    acc1.c = c3.combiner().apply(acc1.c, acc2.c);
                    return acc1;
                },
                acc -> finisher.apply(c1.finisher().apply(acc.a), c2.finisher().apply(acc.b), c3.finisher().apply(acc.c)),
                c.toArray(new Characteristics[c.size()])
               );
    }
    

    and finally use it with

    Content content = contentList.stream().collect(combining(
        Collectors.mapping(Content::getA, Collectors.joining(", ")),
        Collectors.mapping(Content::getB, Collectors.joining(", ")),
        Collectors.mapping(Content::getC, Collectors.joining(", ")), 
        Content::new
    ));
    

提交回复
热议问题