This question already has answers here:
Stream - Collect by property and max
                                
                                    (3个答案)
                                
                        
                                22天前关闭。
            
                    
给定以下示例类:

class Foo{
    String name;
    int value;
    public Foo(String name, int value) {
        this.name = name;
        this.value = value;
    }
    // getters, setters, toString & equals
}


以及foos列表:

List<Foo> fooList = List.of(new Foo("A",1), new Foo("A",2),
                                new Foo("B",1),
                                new Foo("C",1),
                                new Foo("D",1), new Foo("D",2), new Foo("D",3)
                            );


我想得到一个按名称区分的foos列表,如果有多个Foos,我想保留一个具有最高值的foos。

我发现了这个java-8-distinct-by-property问题,以按名称区分列表中的各个元素,该问题使用此方法来获取不同的元素:

public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
    Set<Object> seen = ConcurrentHashMap.newKeySet();
    return t -> seen.add(keyExtractor.apply(t));
}


我像这样使用它:

fooList.stream().filter(distinctByKey(Foo::getName)).collect(Collectors.toList());


它可以获取不同的元素,但是如果有两个或多个具有相同名称的元素,则将第一个元素保留在列表中,并且我无法添加条件以使该元素具有最高值。

另一种选择是使用分组方式:

Map<String,List<Foo>> map = fooList.stream().collect(Collectors.groupingBy(f -> f.getName()));


在这里,我不知道如何从地图到列表中收集具有最高值的Foos。

通过第一种方法,我得到:

Foo{name=A, value=1}
Foo{name=B, value=1}
Foo{name=C, value=1}
Foo{name=D, value=1}


第二个:

A=[Foo{name=A, value=1}, Foo{name=A, value=2}]
B=[Foo{name=B, value=1}]
C=[Foo{name=C, value=1}]
D=[Foo{name=D, value=1}, Foo{name=D, value=2}, Foo{name=D, value=3}]


我如何获得以下物品的清单:

Foo{name=A, value=2}
Foo{name=B, value=1}
Foo{name=C, value=1}
Foo{name=D, value=3}

最佳答案

您可以使用groupBy(classifier, downstream)方法。


  分类函数将元素映射到某些键类型K。下游收集器对类型T的元素进行操作,并产生类型D的结果。结果收集器产生Map。


片段

fooList.stream().collect(
        Collectors.groupingBy(Foo::getName,
                Collectors.collectingAndThen(
                        Collectors.maxBy(Comparator.comparing(Foo::getValue)),
                        Optional::get
                )
        )
).values().forEach(System.out::println);


输出

Foo{name='A', value=2}
Foo{name='B', value=1}
Foo{name='C', value=1}
Foo{name='D', value=3}

关于java - 按名称区分流API,按值区分最大值,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/59211179/

10-11 21:38