根据独立的谓词流式传输集合并收集到多个结果 [英] Stream a collection and collect into multiple results depending on independent predicates

查看:18
本文介绍了根据独立的谓词流式传输集合并收集到多个结果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正盯着一些我试图将其转换为纯函数式风格的命令式代码.基本上在 inputSet 上有一个迭代的 for 循环,我在其中检查 3 个谓词并根据哪个谓词匹配填充 3 个 outputSets.输出集可以重叠.如何使用 Java 8 流/映射/过滤器/等以纯函数方式执行此操作?

I am staring at some imperative code which I am trying to convert to a purely functional style. Basically there is a iterative for-loop over inputSet in which I check 3 predicates and fill 3 outputSets depending on which predicate matches. The output sets can be overlapping. How can I do this in a pure functional way using Java 8 streams/map/filter/ etc.?

推荐答案

最简单的解决方案(除了保持原样更容易)是创建三个单独的流:

The easiest solution (except leaving everything as is which is even easier) is to create three separate streams:

Set<MyObj> set1 = inputSet.stream().filter(pred1).collect(Collectors.toSet());
Set<MyObj> set2 = inputSet.stream().filter(pred2).collect(Collectors.toSet());
Set<MyObj> set3 = inputSet.stream().filter(pred3).collect(Collectors.toSet());

如果你有一个谓词列表,你可以创建一个相应的集合列表作为结果:

If you have a List of predicates, you can create a corresponding List of sets as a result:

List<Predicate<MyObj>> predicates = Arrays.asList(pred1, pred2, pred3);
List<Set<MyObj>> result = predicates.stream()
        .map(pred -> inputSet.stream().filter(pred).collect(Collectors.toSet()))
        .collect(Collectors.toList());

这里结果列表中的第一个集合对应于第一个谓词,依此类推.

Here the first set in the resulting list corresponds to the first predicate and so on.

如果您真的想一次性处理您的输入(无论出于何种原因),您可以为此编写一个特殊的收集器.这是一个非常普遍的:

If you really want to process your input in single pass (for whatever reason), you may write a special collector for this. Here's one which is quite universal:

public static <T, A, R> Collector<T, ?, List<R>> multiClassify(
        List<Predicate<T>> predicates, Collector<? super T, A, R> downstream) {
    Supplier<A> dsSupplier = downstream.supplier();
    BiConsumer<A, ? super T> dsAccumulator = downstream.accumulator();
    BinaryOperator<A> dsCombiner = downstream.combiner();

    Supplier<List<A>> supplier = () -> Stream.generate(dsSupplier)
            .limit(predicates.size()).collect(Collectors.toList());

    BiConsumer<List<A>, T> accumulator = (list, t) -> IntStream
            .range(0, predicates.size()).filter(i -> predicates.get(i).test(t))
            .forEach(i -> dsAccumulator.accept(list.get(i), t));

    BinaryOperator<List<A>> combiner = (l1, l2) -> IntStream.range(0, predicates.size())
            .mapToObj(i -> dsCombiner.apply(l1.get(i), l2.get(i)))
            .collect(Collectors.toList());

    Characteristics[] dsCharacteristics = downstream.characteristics().toArray(
            new Characteristics[0]);
    if (downstream.characteristics().contains(Characteristics.IDENTITY_FINISH)) {
        @SuppressWarnings("unchecked")
        Collector<T, ?, List<R>> result = (Collector<T, ?, List<R>>) (Collector<T, ?, ?>) 
            Collector.of(supplier, accumulator, combiner, dsCharacteristics);
        return result;
    }
    Function<A, R> dsFinisher = downstream.finisher();
    Function<List<A>, List<R>> finisher = l -> l.stream().map(dsFinisher)
           .collect(Collectors.toList());
    return Collector.of(supplier, accumulator, combiner, finisher, dsCharacteristics);
}

它接受一个谓词列表并返回每个谓词的下游收集器结果列表.使用示例:

It takes a list of predicates and returns list of downstream collector results for each predicate. Usage example:

List<String> input = asList("abc", "ade", "bcd", "cc", "cdac");

List<Predicate<String>> preds = asList(
        s -> s.length() == 3, 
        s -> s.startsWith("a"), 
        s -> s.endsWith("c"));
List<Set<String>> result = input.stream().collect(multiClassify(preds, Collectors.toSet()));
// [[bcd, abc, ade], [abc, ade], [cc, abc, cdac]]

这篇关于根据独立的谓词流式传输集合并收集到多个结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆