Как свести все элементы в потоке к общему полю?

У меня есть 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;
}
Основы программирования на Java
Основы программирования на Java
Java - это высокоуровневый объектно-ориентированный язык программирования, основанный на классах.
Концепции JavaScript, которые вы должны знать как JS программист!
Концепции JavaScript, которые вы должны знать как JS программист!
JavaScript (Js) - это язык программирования, объединяющий HTML и CSS с одной из основных технологий Всемирной паутины. Более 97% веб-сайтов используют...
1
0
156
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

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

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;

Могу ли я также пропустить первый элемент в потоке (поскольку он уже был оценен)?

membersound 22.05.2019 14:34

можно добавить skip(1) в поток, хотя прирост производительности незначителен

Sharon Ben Asher 22.05.2019 14:42
    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;
    }

дубликат моего ответа и слишком подробный

Sharon Ben Asher 22.05.2019 13:49

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

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

Проклятье! .reduce((t1, t2) -> t1 == t2? t1: -1)... je suis une идиоте

Eugene 22.05.2019 15:19

Другие вопросы по теме