Java Streams –如何按值分组并找到每个组的最小值和最大值?

对于我的示例,拥有汽车对象,并根据模型(分组依据)发现了最小和最大价格值。

List<Car> carsDetails = UserDB.getCarsDetails();

Map<String, DoubleSummaryStatistics> collect4 = carsDetails.stream()

.collect(Collectors.groupingBy(Car::getMake, Collectors.summarizingDouble(Car::getPrice)));

collect4.entrySet().forEach(e->System.out.println(e.getKey()+" "+e.getValue().getMax()+" "+e.getValue().getMin()));

output :

Lexus 94837.79 17569.59

Subaru 96583.25 8498.41

Chevrolet 99892.59 6861.85

但是我找不到哪个汽车对象具有最高和最低价格。我怎样才能做到这一点?

回答:

如果您只对Car每个组感兴趣,则可以使用,例如

Map<String, Car> mostExpensives = carsDetails.stream()

.collect(Collectors.toMap(Car::getMake, Function.identity(),

BinaryOperator.maxBy(Comparator.comparing(Car::getPrice))));

mostExpensives.forEach((make,car) -> System.out.println(make+" "+car));

但是,由于您想要最昂贵和最便宜的产品,因此需要以下内容:

Map<String, List<Car>> mostExpensivesAndCheapest = carsDetails.stream()

.collect(Collectors.toMap(Car::getMake, car -> Arrays.asList(car, car),

(l1,l2) -> Arrays.asList(

(l1.get(0).getPrice()>l2.get(0).getPrice()? l2: l1).get(0),

(l1.get(1).getPrice()<l2.get(1).getPrice()? l2: l1).get(1))));

mostExpensivesAndCheapest.forEach((make,cars) -> System.out.println(make

+" cheapest: "+cars.get(0)+" most expensive: "+cars.get(1)));

由于没有与之等效的通用统计对象,因此该解决方案带来了一些不便DoubleSummaryStatistics。如果这种情况不止一次发生,那么值得用这样的类填补空白:

/**

* Like {@code DoubleSummaryStatistics}, {@code IntSummaryStatistics}, and

* {@code LongSummaryStatistics}, but for an arbitrary type {@code T}.

*/

public class SummaryStatistics<T> implements Consumer<T> {

/**

* Collect to a {@code SummaryStatistics} for natural order.

*/

public static <T extends Comparable<? super T>> Collector<T,?,SummaryStatistics<T>>

statistics() {

return statistics(Comparator.<T>naturalOrder());

}

/**

* Collect to a {@code SummaryStatistics} using the specified comparator.

*/

public static <T> Collector<T,?,SummaryStatistics<T>>

statistics(Comparator<T> comparator) {

Objects.requireNonNull(comparator);

return Collector.of(() -> new SummaryStatistics<>(comparator),

SummaryStatistics::accept, SummaryStatistics::merge);

}

private final Comparator<T> c;

private T min, max;

private long count;

public SummaryStatistics(Comparator<T> comparator) {

c = Objects.requireNonNull(comparator);

}

public void accept(T t) {

if(count == 0) {

count = 1;

min = t;

max = t;

}

else {

if(c.compare(min, t) > 0) min = t;

if(c.compare(max, t) < 0) max = t;

count++;

}

}

public SummaryStatistics<T> merge(SummaryStatistics<T> s) {

if(s.count > 0) {

if(count == 0) {

count = s.count;

min = s.min;

max = s.max;

}

else {

if(c.compare(min, s.min) > 0) min = s.min;

if(c.compare(max, s.max) < 0) max = s.max;

count += s.count;

}

}

return this;

}

public long getCount() {

return count;

}

public T getMin() {

return min;

}

public T getMax() {

return max;

}

@Override

public String toString() {

return count == 0? "empty": (count+" elements between "+min+" and "+max);

}

}

将其添加到您的代码库后,您可以像

Map<String, SummaryStatistics<Car>> mostExpensives = carsDetails.stream()

.collect(Collectors.groupingBy(Car::getMake,

SummaryStatistics.statistics(Comparator.comparing(Car::getPrice))));

mostExpensives.forEach((make,cars) -> System.out.println(make+": "+cars));

如果getPrice回报double,也可能是使用更有效Comparator.comparingDouble(Car::getPrice)的替代Comparator.comparing(Car::getPrice)

以上是 Java Streams –如何按值分组并找到每个组的最小值和最大值? 的全部内容, 来源链接: utcz.com/qa/433229.html

回到顶部