如何将流中的所有元素简化为一个公共字段?

时间:2019-05-22 11:33:10

标签: java java-stream

我有一个List<Person>,并且想检查所有人是否都相同。TypePerson。在这种情况下,这是根据年龄得出的。如果所有相同,则返回该通用类型。

以下方法可以工作,但我认为将人类型首先收集到集合中并不是最佳选择,然后仅返回其中的第一个元素。可以优化以下内容吗?

class Person {
    int age;
}

enum TypePerson {
    BABY, CHILD, ADULT;
}

//should check if the list contains only a single person type, and return it.
TypePerson reduceToSinglePersonType(List<Person> persons) {
    Set<TypePerson> types = persons.stream()
                .map(p -> resolvePersonType(person.age))
                .collect(Collectors.toSet());

    if (types.size() != 1) return null; //nothing in common
    return types.iterator().next();
}

TypePerson resolvePersonType(int age) {
    if (age < 2) return BABY;
    if (age < 10) return CHILD;
    return ADULT;
}

3 个答案:

答案 0 :(得分:2)

如果只需要(仅)减少值,则无需构建集合。只需将所有项目与列表中第一项的值进行比较,如果全部匹配,则将其返回:

if (!persons.isEmpty()) {
    // get the first (only?) person type
    TypePerson possiblyOnlyType = resolvePersonType(persons.get(0).age);
    // if all items in list have same value...
    if (persons.stream()
            .allMatch(person -> resolvePersonType(person.age) == possiblyOnlyType)) {
        return possiblyOnlyType;
    }
}
return null;

答案 1 :(得分:2)

如果可以的话,那将是完美的

TypePerson reduceToSinglePersonType(List<Person> persons) {
    return persons.stream()
        .map(p -> resolvePersonType(p.age))
        .reduce((t1, t2) -> t1 == t2? t1: null) // does not work
        .orElse(null);
}

但是很遗憾,reduce的值不能为null,并且由于类型是enum,因此没有其他超出范围的值来表示无效值值含糊的状态。

一种解决方法是处理序号,这使我们可以将-1用作无效值

TypePerson reduceToSinglePersonType(List<Person> persons) {
    int o = persons.stream()
        .mapToInt(p -> resolvePersonType(p.age).ordinal())
        .reduce((t1, t2) -> t1 == t2? t1: -1)
        .orElse(-1);
    return o < 0? null: TypePerson.values()[o];
}

或者我们使用Optional,它真正支持缺失值

TypePerson reduceToSinglePersonType(List<Person> persons) {
    return persons.stream()
        .map(p -> Optional.of(resolvePersonType(p.age)))
        .reduce((o1, o2) -> o1.equals(o2)? o1: Optional.empty())
        .flatMap(Function.identity())
        .orElse(null);
}

或者我们暂时放弃类型安全性,以便能够使用其他类型的对象表示无效状态

TypePerson reduceToSinglePersonType(List<Person> persons) {
    return persons.stream()
        .<Object>map(p -> resolvePersonType(p.age))
        .reduce((o1, o2) -> o1 == o2? o1: "invalid")
        .filter(o -> o != "invalid")
        .map(TypePerson.class::cast)
        .orElse(null);
}

答案 2 :(得分:0)

    TypePerson reduceToSinglePersonType(List<Person> persons) {
        if (persons.size() == 0) return null; // no type at all

        // the type, if the rest are of the same type
        TypePerson candidate = resolvePersonType(persons.get(0).age);

        // check whether other persons are of same type
        for (int i=1; i<persons.size(); i++) {
            if (resolvePersonType(persons.get(1).age) != candidate) return null; // candidate type is not unique
        }

        return candidate;
    }