使用Java 8从对象列表中查找中值

sz81bmfz  于 2023-05-05  发布在  Java
关注(0)|答案(6)|浏览(137)

我有两个类的结构是这样的:

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对象的List,每个Person对象都可以获得一个Age值。
如果我得到了Person对象的List,有没有一种好的方法可以使用Java 8来找到所有Person对象中的中位数Age值(Stream不支持中位数,但还有其他方法吗)?

Double medianAge;
if(!company.getPerson().isEmpty) {
     medianAge = company.getPerson() //How to do this in Java 8?
}
xggvc2p6

xggvc2p61#

您可以使用

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;

而不是

xriantvc

xriantvc2#

强制性的Guava方式。

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);

尽管Guava 31.1 Quantiles仍然标注为@Beta。

a5g8bdjr

a5g8bdjr3#

下面是@Holger的答案的简化版本,它也适用于IntStreamLongStream,并且在空流的情况下避免了NoSuchElementException

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()

jhkqcmku

jhkqcmku4#

下面是使用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);
                    }
                }));

它不修改现有列表或要求对它们进行排序。

qni6mghb

qni6mghb5#

如果列表未排序,则可以使用以下代码:

int middle = list.size()/2;
Integer value = list.stream().filter(i -> list.indexOf(i) == middle).collect(Collectors.toList()).get(0);
System.out.println(value);
utugiqy6

utugiqy66#

你可以使用lambda表达式约简来获得列表的中位数:

Integer median = Person
   .stream()
   .map(Person::getAge)
   .filter(n -> n.length()/2);

相关问题