#java #collections #java-8 #group-by #collectors
#java #Коллекции #java-8 #группировка по #сборщики
Вопрос:
У меня есть функция, которая возвращает Map<String, Set<String>>
код, предшествующий java 8:
Map<String, Set<String>> degreeMap = new HashMap<>();
for(Course course : courses){
Set<String> cList = degreeMap.get(course.getCourseLevel().toString());
if(Objects.nonNull(cList)){
cList.addAll(course.getMasterDegree()); //this is what i want to append to the old set
degreeMap.put(course.getCourseLevel().toString(), cList);
} else{
degreeMap.put(course.getCourseLevel().toString(), new HashSet<>(course.getMasterDegree()));
}
}
return degreeMap;
Которые возвращают карту courselevel -> набор степеней.
Например, он считывает все курсы и возвращает карту типа:
{"undergraduate" : ["BTech", "BSc", "BE"],
"masters": ["MTech", "MBA"],
"Executive": ["PGDBM", "EECP"]}
Вот мой класс курса:
public class Course {
private List<String> masterDegree;
private CourseLevel courseLevel;
}
Но я хочу написать этот фрагмент кода в стиле Java 8. Для этого я попробовал это:
Map<String, Set<String>> degreeMap = courses.stream().collect(
Collectors.groupingBy(c -> c.getCourseLevel().toString(),
Collectors.mapping(c -> c.getMasterDegree(), Collectors.toSet()))
);
который не работает, и я получаю следующую ошибку времени компиляции по этому поводу:
не существует экземпляров переменных типа, чтобы список соответствовал строке переменная вывода T имеет несовместимые границы: ограничения равенства: Строка нижние границы: Список
Любое предложение, как этого добиться?
Комментарии:
1. Мне кажется, что вы ищете
flatMapping
эквивалент Java-9 в более старой версии.2. @GhostCat попытался отредактировать вопрос, чтобы он был достаточно актуальным. надеюсь, теперь все ясно.
3. @Naman спасибо за разрешение этой битвы: P
4.
for(Course course : courses) degreeMap.computeIfAbsent(course.getCourseLevel() .toString(), x -> new HashSet<>()) .addAll(course.getMasterDegree());
Кстати, даже в вашей версии до Java 8 никогда не было причины для того, чтобыput
тот же списокMap
снова появлялся послеaddAll
.
Ответ №1:
Не проверено, но похоже, вы ищете что-то вроде:
return courses.stream()
.collect(Collectors.toMap(course -> course.getCourseLevel().toString(),
course -> new HashSet<>(course.getMasterDegree()),
(set1, set2) -> Stream.of(set1, set2)
.flatMap(Set::stream).collect(Collectors.toSet())));
Комментарии:
1. В этом случае,
(set1, set2) -> { set1.addAll(set2); return set1; }
очевидно, является предпочтительной функцией слияния…
Ответ №2:
Возможно, вас заинтересует метод Collectors.toMap() .
Вот пример, который вам может понадобиться настроить, поскольку я его не тестировал.
Map<String, Set<String>> degreeMap = courses.stream()
.collect(
Collectors.toMap(
item -> item.getCourseLevel().toString(), //your key mapping
item -> item.getMasterDegree(), //your value mapping
(oldValue, newValue) -> { //your process of aggregation
if (null == oldValue) {
return newValue;
} else {
oldValue.addAll(newValue);
return oldValue;
}
},
LinkedHashMap::new //your result initialiser
)
);
Кроме того, еще один совет: вам не нужно получать по ключу и проверять наличие null, вы можете использовать методы .compute() , .computeIfAbsent() , .computeIfPresent() на карте
Ответ №3:
Я не думаю, что вам нужно выражение lamda, вам следует реорганизовать свои коды, чтобы сделать их понятными.
// supposed to be initialied with non-empty values
// Map<String, Set<String>> degreeMap = ...
for(Course course : courses){
// something like below
String key = course.getCourseLevel().toString();
// degreeSet should not be null
Set<String> degreeSet = course.getMasterDegree();
// TODO: check nullable
degreeSet.putAll(degreeMap.get(key));
degreeMap.put(key, degreeSet);
}
return degreeMap;