У меня есть 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;
}
Если все, что вам нужно, это (единственное) уменьшенное значение, вам не нужно создавать набор. просто сравните все элементы со значением первого в списке и верните его, если все они совпадают:
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;
можно добавить skip(1)
в поток, хотя прирост производительности незначителен
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;
}
дубликат моего ответа и слишком подробный
Было бы идеально, если бы мы могли сделать
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 идиоте
Могу ли я также пропустить первый элемент в потоке (поскольку он уже был оценен)?