Сторнирование HashMap с карты <String, Boolean> на карту <Boolean, List <String>> - PullRequest
4 голосов
/ 26 сентября 2011

Есть ли более элегантный / встроенный способ инвертировать ключи и значения Hashmap?

В настоящее время у меня есть следующее.

Ответы [ 4 ]

6 голосов
/ 26 сентября 2011

Вы можете рассмотреть возможность использования одной из Guava * Multimap реализаций. Например:

private Multimap<Boolean, String> reverseMap(Map<String, Boolean> permissions) {
   Multimap<Boolean, String> multimap = ArrayListMultimap.create();
   for (Map.Entry<String, Boolean> entry : permissions.entrySet()) {
      multimap.put(entry.getValue(), entry.getKey());
   }
   return multimap;
}

Или, в более общем смысле:

private static <K, V> Multimap<V, K> reverseMap(Map<K, V> source) {
   Multimap<V, K> multimap = ArrayListMultimap.create();
   for (Map.Entry<K, V> entry : source.entrySet()) {
      multimap.put(entry.getValue(), entry.getKey());
   }
   return multimap;
}
1 голос
/ 26 сентября 2011

Первое, что нужно отметить, это то, что вам на самом деле не нужна обратная карта, если ваши значения только true или false. Это будет иметь смысл, если у вас более широкий диапазон значений.

Один простой (но не очень элегантный) способ получить записи с определенным значением:

public static <T, E> Set<T> getKeysByValue(Map<T, E> map, E value) {
     Set<T> keys = new HashSet<T>();
     for (Entry<T, E> entry : map.entrySet()) {
         if (entry.getValue().equals(value)) {
             keys.add(entry.getKey());
         }
     }
     return keys;
}

Вы можете видеть, что это не так хорошо, если вам нужно звонить время от времени. Имеет смысл иметь две разные карты (прямую и обратную) и добавлять записи в обе. Вы не можете использовать карты Bidi, так как между ключами и значениями нет отношения 1: 1.

ОБНОВЛЕНИЕ: следующее решение не будет работать. Смотрите комментарии. Вы также можете рассмотреть возможность использования TreeMap и сортировать его по значению. Таким образом, вы можете иметь отсортированный набор, вызывая map.entrySet() в любое время (сначала запрещает ввод, затем разрешает). Недостатком является то, что это только один набор.

ValueComparator bvc =  new ValueComparator(map);
TreeMap<String,Boolean> sorted_map = new TreeMap(bvc);

class ValueComparator implements Comparator {
  Map base;

  public ValueComparator(Map base) {
      this.base = base;
  }

  public int compare(Object a, Object b) {
    return (Boolean)base.get(a).compareTo((Boolean)base.get(b));
  }
}

1 голос
/ 26 сентября 2011

Я бы сделал что-то подобное (но если вам нужно делать это часто, рассмотрите Guava), только заменив List на Set (кажется немного более последовательным) и предварительно заполнив обратную карту:

private Map<Boolean, Set<String>> reverseMap(Map<String, Boolean> permissions) {
    Map<Boolean, Set<String>> returnvalue = new HashMap<Boolean, Set<String>>();
    returnvalue.put(Boolean.TRUE, new HashSet<String>());
    returnvalue.put(Boolean.FALSE, new HashSet<String>());
    for (Entry<String, Boolean> entry : permissions.entrySet()) 
        returnvalue.get(entry.getValue()).add(entry.getKey());
    return returnvalue;
}
0 голосов
/ 16 октября 2013

Guava 's BiMap уже предоставляет метод для изменения его пар ключ-значение.Возможно, вы могли бы изменить интерфейс рассматриваемого Map на BiMap или использовать следующий код:

private BiMap<Boolean, String> reverseMap(Map<String, Boolean> permissions) {
   BiMap<String, Boolean> bimap = HashBiMap.create(permissions);
   return bimap.inverse();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...