Мультикарта (multi-map) может пригодиться в реальной работе или на собеседовании. Почему-то в некоторых компаниях при приёме на работу любят давать алгоритмические задачки на её использование (лично я так не поступаю).
По сути это обычная карта (Map) в которой значением является коллекция (List или Set).
Сейчас в JCF (Java Collections Framework) нет готового класса для Multimap.
До выхода Java 8 приходилось логику работы писать вручную.
Например так.
Допустим, нам поступают такие данные:
Moscow=ru
Omsk=ru
Tula=ru
NY=us
LA=us
London=uk и т.д.
Их нужно представить в виде:
ru=Moscow, Omsk, Tula
us=NY, LA
uk=London
Тогда логику можно реализовать, например, в таком виде:
import java.util.*;
public class Main {
public static void main(String[] args) {
// Получили город и страну
String city = "Moscow", country = "ru";
// Карта куда всё будем складывать
Map> map = new HashMap<>();
List list = map.get(country);
// Если это наш первый раз,
// тогда создаем список и кладем его по ключу (название страны)
if (list == null) {
list = new ArrayList<>();
map.put(country, list);
}
list.add(city);
}
}
Это не удобно, поэтому многие используют Multimap из Apache Commons или Google Guava.
В восьмой Java, с помощью анонимных функций и нового API, логику можно сделать однострочником:
// В случае первого раза вызывать функцию: (key) -> value
map.computeIfAbsent(country, (k)-> new ArrayList()).add(city);
N.B.: Совет использовать computeIfAbsent для создания мультикарты явно указан в документации.
Если же у нас на входе готовая карта, то её можно прокрутить foreach (хотя это не очень красиво):
Например так:
Map map = new HashMap<>();
map.put("Madrid", "es");
map.put("Moscow", "ru");
map.put("Omsk", "ru");
map.put("London", "uk");
Map> result = new HashMap<>();
map.forEach((city, country) -> {
result.computeIfAbsent(country, (k) -> new ArrayList()).add(city);
});
Интересней было бы воспользоваться Stream API.
Например так:
import java.util.*;
import static java.util.Map.Entry;
import static java.util.stream.Collectors.*;
public class Main {
public static void main(String[] args) {
Map map = new HashMap<>();
map.put("Madrid", "es");
map.put("Moscow", "ru");
map.put("Omsk", "ru");
map.put("London", "uk");
// Сгруппировать по стране (Entry::getValue),
// а название города Entry::getKey записывать в список (toList)
Map> m = map.entrySet().stream().collect(
// Группировать по названию страны (es, ru, uk и т.д.)
groupingBy(Entry::getValue,
// Запихиваем город (Moscow, London и т.д.) в список (toList)
mapping(Entry::getKey, toList())));
}
}
Здесь используется функциональное программирование, восприятие которого требует определенного “привыкания”. Поскольку я периодически сталкиваюсь как со сторонниками “императивщины”, так и со сторонниками “функциональщины”, могу сказать, что у каждого своя правда. В каждом конкретном случае следует исходить из конечных целей.
В качестве причины почему действительно стоит изучать функциональный поход могу сказать, что игнорировать его сейчас уже нельзя, т.к. в противном случае программист просто перестанет понимать программы написанные другими программистами. Когда появилась 5-ая Java было очень много ненавистников дженериков, сейчас польза их очевидна, а умение их использовать просто необходимо.