当前位置: 首页 > 面试题库 >

流收集并根据独立谓词收集成多个结果

凌经赋
2023-03-14
问题内容

我盯着一些命令性代码,试图将其转换为纯函数式样式。基本上有一个迭代的for循环,inputSet在该循环中,我检查3个谓词,并outputSets根据匹配的谓词填充3个谓词。输出集可以重叠。如何使用Java
8 Streams / map / filter /等以纯功能方式实现此目的?


问题答案:

最简单的解决方案(除了将所有内容保留为更容易之外)是创建三个单独的流:

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());

如果有谓词列表,则可以创建相应的集合列表:

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());

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

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

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);
}

它获取谓词列表,并返回每个谓词的下游收集器结果列表。用法示例:

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]]


 类似资料:
  • 我想获取地图的值,找到min值,并为地图的每个条目构造一个新的CodesWitMinValue实例。我希望使用Java11个流,我可以在多行中使用多个流(一个用于min值,一个用于转换)来实现这一点。是否可以使用java 11流和收集器在单行中实现?谢谢。

  • 为了更好地理解新的流API,我试图转换一些旧代码,但我被困在这一个。 我似乎无法为它创建有效的收集器:

  • 我的Ionic 5应用程序中有以下Firestore数据库结构。 书(集合) {bookID}(带有book字段的文档) 赞(子集合) {userID}(文档名称作为带有字段的用户ID) 集合中有文档,每个文档都有一个子集合。Like collection的文档名是喜欢这本书的用户ID。 我正在尝试进行查询以获取最新的,同时尝试从子集合中获取文档以检查我是否喜欢它。 我在这里做的是用每个图书ID调

  • 我使用的是java 11,我有一个名为MyObject的对象列表,看起来像这样 我想使用流将这些对象收集到地图中 我试着用收集器来做。toMap(),但似乎不可能做到这一点 我的问题是可以制作一张地图吗

  • 我已经在JDK 1.8上工作了几天,遇到了一些类似的代码: 现在,对于一直在使用流()的人来说,它可能看起来既简单又干净,但我找不到实现方法的实际类。 当我说列表时,我有以下问题。流(): 我从哪里获取? 他们是如何在不实际“干扰”现有集合的情况下实现它的?(假设他们没有接触它们) 我确实试着浏览了java的文档。util。AbstractCollection和java。util。Abstract

  • 问题内容: 我想接受输入并对其应用并行流,然后我希望将输出作为列表。输入可以是任何列表或可以对其应用流的任何集合。 我在这里担心的是,如果我们要输出为map,我们可以从java中选择一个选项,例如 但是我看不到以线程安全的方式从并行流收集以提供列表作为输出的选项。我看到那里还有一个选择 通过这种方式,我们可以在collect方法中提供各种并发实现。但是我认为java.util.concurrent