代码之家  ›  专栏  ›  技术社区  ›  Jin Kwon

如何通过流中的某个最大值来过滤流?

  •  1
  • Jin Kwon  · 技术社区  · 3 年前

    假设我有一个如下对象的流。

    class MyObject {
        private Some some; // Comparable
        private Other value
    }
    

    有没有一个成语在一个链条上做以下事情?

    • 给定 Stream<MyObject> ,
    • 查找的最大值 some
    • 地图 value 谁的 一些 是最大值。

    就好像,

    final List<MyObject> list = getList();
    final Some max = list.stream().max(Comparator.naturalOrder())
    final List<Other> list = list.stream()
            .filter(e -> Objects.equals(e.some, max)
            .map(e -> e.getValue()).collect(toList());
    
    1 回复  |  直到 3 年前
        1
  •  1
  •   M A    3 年前

    如果必须一次性完成,则可以编写一个自定义收集器,将流缩减为最大元素列表。以下是基于 this answer 斯图尔特·马克斯。

    List<MyObject> maxList = list.stream()
                                 .collect(maxList(Comparator.comparing(MyObject::getSome)));
    
    static <T> Collector<T,?,List<T>> maxList(Comparator<? super T> comp) {
        return Collector.of(
            ArrayList::new,
            (list, t) -> {
                int c;
                if (list.isEmpty() || (c = comp.compare(t, list.get(0))) == 0) {
                    list.add(t);
                } else if (c > 0) {
                    list.clear();
                    list.add(t);
                }
            },
            (list1, list2) -> {
                if (list1.isEmpty()) {
                    return list2;
                } 
                if (list2.isEmpty()) {
                    return list1;
                }
                int r = comp.compare(list1.get(0), list2.get(0));
                if (r < 0) {
                    return list2;
                } else if (r > 0) {
                    return list1;
                } else {
                    list1.addAll(list2);
                    return list1;
                }
            });
    }
    

    收集器将维护一个用于结果的ArrayList,并将每个元素累积到其中,检查该元素与当前列表的第一个元素的比较情况。零件 c = comp.compare(t, list.get(0))) == 0 将检查元素是否具有相同的最大值,如果是,则将其添加到列表中。

        2
  •  1
  •   ernest_k Petronella    3 年前

    如果您使用Java 12+,您可以使用 Collectors.teeing :

    List<Other> maxObjects = list.stream().collect(
        Collectors.teeing(
            Collectors.maxBy(Comparator.comparing(MyObject::getSome)),
            Collectors.groupingBy(
                MyObject::getSome,
                Collectors.mapping(
                    MyObject::getValue, 
                    Collectors.toList())),
            (max, groups) -> max.map(MyObject::getSome).map(groups::get).orElse(null)));