Инвертировать карту | Значения ---> Ключи - PullRequest
0 голосов
/ 17 марта 2020

Я хочу иметь возможность инвертировать заданную HashMap, которая имеет несколько ключей, может указывать на одно и то же значение.

HashMap<String, String> cities = new HashMap<String, String>();

        cities.put("Manchester", "UK");
        cities.put("London", "UK");
static HashMap<String, String> inverseMap(HashMap map) {
       // something that has "UK" point to both "Manchester" and "London"

      // if it can be done without using any special Java 8 feature, that would be great
}

Я не уверен, с чего начать.

Ответы [ 5 ]

1 голос
/ 17 марта 2020

Сделай так. По сути, он использует функцию слияния, которая объединяет значения для дубликата ключа.

  • Создание новой карты
  • Использование значений старой карты для ключей к новой
  • Если новая карта не имеет значения для ключа, поместите значение в новую карту
  • В противном случае объедините значение со старым значением для этого ключа
        HashMap<String, String> cities = new HashMap<String, String>();

        cities.put("Manchester", "UK");
        cities.put("London", "UK");
        cities.put("New York", "US");
        cities.put("Chicago", "US");

        Map<String,String> inverted = new HashMap<>();
        for (String key : cities.keySet()) {
            String newKey = cities.get(key);
            String value = inverted.get(newKey);
            if (value == null) {
                inverted.put(newKey, key);
            } else {
                value = value + ", " + key;
                inverted.put(newKey, value);
            }

        }
        for (Entry<String,String> e : inverted.entrySet()) {
            System.out.println(e.getKey() + " -> " + e.getValue());
        }

Он печатает

UK -> Manchester, London
US -> New York, Chicago

Поскольку вы не указали, как обрабатывать дубликаты ключей. Я мог бы также сохранить его в Map<String,List<String>>

0 голосов
/ 17 марта 2020

Вы можете перебрать набор записей вашей исходной карты и использовать значения (код страны) в качестве ключа и добавить каждый ключ (города) в список:

static HashMap<String, List<String>> inverseMap(HashMap<String, String> map) {
   HashMap<String, List<String>> countryToCity = new HashMap<>();
   for(Map.Entry<String,String> entry: map.entrySet()){
       countryToCity.computeIfAbsent(entry.getValue(), k -> new ArrayList<>()).add(entry.getKey());
   }
   return countryToCity;
}
0 голосов
/ 17 марта 2020

Это то, что вы ищете?

Map<String, String> cities = new HashMap<>();
cities.put("Manchester", "UK");
cities.put("London", "UK");
Map<String, List<String>> reverseMap = new HashMap<>();
for (Entry<String, String> entry : cities.entrySet()) {
     List<String> list = reverseMap.get(entry.getValue());
     if (list == null) {
         list = new ArrayList<>();
         reverseMap.put(entry.getValue(), list);
     }
     list.add(entry.getKey());
}

System.out.println(reverseMap);
0 голосов
/ 17 марта 2020

Поскольку несколько ключей могут содержать одно и то же значение, вы должны будете иметь возможность хранить несколько значений для каждого ключа в инвертированной карте. Я рекомендую использовать Set в качестве значения для этого.

  • Создать карту, в которой можно сохранить набор строк в качестве значений
  • Итерация по исходной карте
  • Если страна не найдена на новой карте, создайте там запись
  • Добавьте город на карту

Это также должно работать с Java 7 без зависимостей.

static HashMap<String, Set<String>> inverseMap(HashMap<String,String> map) {
    HashMap<String,Set<String>> inversed=new HashMap<>();
    for(Map.Entry<String,String> entry:map.entrySet()){
        if(!inversed.containsKey(entry.getValue())){
            inversed.put(entry.getValue(),new HashSet<>());
        }
        inversed.get(entry.getValue()).add(entry.getKey());
    }
    return inversed;
}

{Manchester=UK,London=UK} превратится в {UK={Manchester,London}} (порядок может отличаться).

0 голосов
/ 17 марта 2020

Вы можете посмотреть на MultiMap. Это позволяет сопоставить один ключ нескольким значениям.

Это то, что было реализовано в Google Guava https://guava.dev/releases/19.0/api/docs/com/google/common/collect/Multimap.html

ListMultimap<String, String> multimap = ArrayListMultimap.create();
   for (President pres : US_PRESIDENTS_IN_ORDER) {
     multimap.put(pres.firstName(), pres.lastName());
   }
   for (String firstName : multimap.keySet()) {
     List<String> lastNames = multimap.get(firstName);
     out.println(firstName + ": " + lastNames);
   }
... produces output such as:
   Zachary: [Taylor]
   John: [Adams, Adams, Tyler, Kennedy]  // Remember, Quincy!
   George: [Washington, Bush, Bush]
   Grover: [Cleveland, Cleveland]        // Two, non-consecutive terms, rep'ing NJ!

Как и в Apache Коллекции общин https://commons.apache.org/proper/commons-collections/apidocs/org/apache/commons/collections4/MultiValuedMap.html

     MultiValuedMap<K, String> map = new MultiValuedHashMap<K, String>();
     map.put(key, "A");
     map.put(key, "B");
     map.put(key, "C");
    Collection<String> coll = map.get(key);
coll will be a collection containing "A", "B", "C".
...