Как свести все элементы в потоке к общему полю? - PullRequest
1 голос
/ 22 мая 2019

У меня есть 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 ]

2 голосов
/ 22 мая 2019

Было бы идеально, если бы мы могли сделать

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 голосов
/ 22 мая 2019

Если все, что вы хотите - это (только) уменьшенное значение, вам не нужно создавать набор. просто сравните все элементы со значением первого в списке и верните его, если все совпадают:

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;
0 голосов
/ 22 мая 2019
    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;
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...