我有两个结构如下的类:
public class Company {
private List<Person> person;
...
public List<Person> getPerson() {
return person;
}
...
}
public class Person {
private Double age;
...
public Double getAge() {
return age;
}
...
}
基本上,Company类有一个Person对象列表,每个Person对象都可以获得Age值。
如果我得到Person对象的List,是否有一种很好的方法可以使用Java 8在所有Person对象中找到Age Age值(Stream不支持中位数但是还有其他的东西)?
Double medianAge;
if(!company.getPerson().isEmpty) {
medianAge = company.getPerson() //How to do this in Java 8?
}
答案 0 :(得分:8)
您可以使用
List<Person> list = company.getPerson();
DoubleStream sortedAges = list.stream().mapToDouble(Person::getAge).sorted();
double median = list.size()%2 == 0?
sortedAges.skip(list.size()/2-1).limit(2).average().getAsDouble():
sortedAges.skip(list.size()/2).findFirst().getAsDouble();
这种方法的优点是它不会修改列表,因此也不依赖于它的可变性。但是,它不一定是最简单的解决方案。
如果您可以选择修改列表,则可以使用
List<Person> list = company.getPerson();
list.sort(Comparator.comparingDouble(Person::getAge));
double median = list.get(list.size()/2).getAge();
if(list.size()%2 == 0) median = (median + list.get(list.size()/2-1).getAge()) / 2;
代替。
答案 1 :(得分:1)
这里是@Holger的简化版本的答案,该答案也适用于IntStream
和LongStream
,并且在空流的情况下避免NoSuchElementException
:< / p>
int size = someList.size();
//replace 'XXX' with 'Int', 'Long', or 'Double' as desired
return someList.stream().mapToXXX(...).sorted()
.skip((size-1)/2).limit(2-size%2).average().orElse(Double.NaN);
如果列表为空而不是抛出NaN
,则会返回NoSuchElementException
。如果您更愿意抛出NoSuchElementException
,只需将.orElse(Double.NaN)
替换为.getAsDouble()
。
答案 2 :(得分:1)
强制性番石榴方式。
import java.util.List;
import java.util.stream.Collectors;
import com.google.common.math.Quantiles;
...
List<Person> people = company.getPerson();
List<Double> ages = people.stream().map(Person::getAge).collect(Collectors.toList());
double median = Quantiles.median().compute(ages);
答案 3 :(得分:0)
这是一个流中使用 Collectors.collectingAndThen
double median = people.stream()
.map(Person::getAge)
.sorted()
.collect(Collectors.collectingAndThen(
Collectors.toList(),
ages -> {
int count = ages.size();
if (count % 2 == 0) { // even number
return (ages.get(count / 2 - 1) + ages.get(count / 2)) / 2;
} else { // odd number
return ages.get(count / 2);
}
}));
它不会修改现有列表或要求对它们进行排序。
答案 4 :(得分:-5)
您可以使用lambda表达式缩减来获得列表的中位数。像这样的东西
Integer median = Person
.stream()
.map(Person::getAge)
.filter(n -> n.length()/2)
;