Java 8 - Stream - 按值分组并查找该对象的最小值和最大值 [英] Java 8 - Stream - Group by value and find min and max value of that object
问题描述
对于我的例子,拥有汽车对象并发现基于模型的最小和最大价格值(分组依据)。
For my example,having car object and found that min and max price value based on model (group by).
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
但我找不到哪个车对象有最高和最低价格。我怎么能这样做?
But i couldn't find which car object have max and min price. How can i do that?
推荐答案
如果您只对一个 Car $ c $感兴趣c>每组,你可以使用,例如
If you were interested in only one Car
per group, you could use, e.g.
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));
但既然你想要最便宜和最便宜的,你需要这样的东西:
But since you want the most expensive and the cheapest, you need something like this:
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)));
这个解决方案带来一些不便,因为没有相当于<的通用统计对象code> DoubleSummaryStatistics 。如果这种情况不止一次发生,那么值得用这样的类填补空白:
This solution bears a bit of inconvenience due to the fact that there is no generic statistics object equivalent to DoubleSummaryStatistics
. If this happens more than once, it’s worth filling the gap with a class like this:
/**
* 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);
}
}
将此添加到您的代码库后,您可以使用它喜欢
After adding this to your code base, you may use it like
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 8 - Stream - 按值分组并查找该对象的最小值和最大值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!