Как перевернуть Map, чтобы ключ стал значением, а значение ключом?
Student student1 = new Student("Ivan", "Ivanov");
Student student2 = new Student("Nikolay", "Petrov");
Student student3 = new Student("Kirill", "Antipov");
Course matematic = new Course("Matematic");
Course philosophy = new Course("Philosophy");
Course english = new Course("English");
Course physics = new Course("Physics");
Course franch = new Course("Franch");
Map<Student, List<Course>> education = new HashMap<Student, List<Course>>();
education.put(student1, Arrays.asList(matematic, english, philosophy));
education.put(student2, Arrays.asList(matematic, english, physics));
education.put(student3, Arrays.asList());
Совсем не понимаю, как это возможно осуществить, не создавая новую карту.
Ответы (4 шт):
Как по мне, то это изобретение велосипеда. Эту проблему давно решили. Например, таким решением есть bimap от guava. Метод, который перевернет Map, называется inverse.
Подробный гид можете найти здесь:
Как-то так (писал тут, так что могут быть ошибки):
var res = new HashMap<Course, List<Student>>();
for (var entry : education.entrySet()) {
var student = entry.getKey();
for (var course : entry.getValue()) {
var list = res.get(course);
if (list == null) res.put(course, list = new ArrayList());
list.add(student);
}
}
Если нужно построить "обратную" мапу вида Map<Course, List<Student>>, можно использовать метод Map::computeIfAbsent, чтобы создать список значений для "нового" ключа, и добавить в него "старый" ключ.
Обобщённое решение для любых пар типов K, V (для итерации используются методы Map::forEach, List::forEach)
public static<K, V> Map<V, List<K>> convert(Map<K, List<V>> map) {
Map<V, List<K>> result = new HashMap<>(); // new LinkedHashMap<>();
map.forEach((key, vals) -> vals.forEach(
v -> result.computeIfAbsent(v, kk -> new ArrayList<>()).add(key)
));
return result;
}
Возможно решение при помощи Stream API, но оно будет более громоздкое
public static<K, V> Map<V, List<K>> convert(Map<K, List<V>> map) {
return map.entrySet()
.stream() // Stream<Map.Entry<K, List<V>>>
.flatMap(e -> e.getValue().stream() // Stream<V>
.map(v -> Map.entry(v, e.getKey()))
) // Stream<Map.Entry<V, K>>
.collect(Collectors.groupingBy(
Map.Entry::getKey,
Collectors.mapping(Map.Entry::getValue, Collectors.toList())
));
}
HashMap<String, String> countryCapitalMap = new HashMap<>();
for (Map.Entry<String,String> enty: capitalCountryMap.entrySet()) {
countryCapitalMap.put(enty.getValue(), enty.getKey());
}
я сделала так