【问题标题】:Reversing a HashMap from Map<String, Boolean> to Map<Boolean, List<String>>将 HashMap 从 Map<String, Boolean> 反转为 Map<Boolean, List<String>>
【发布时间】:2011-11-24 20:46:12
【问题描述】:

是否有更优雅/内置的方式来反转 Hashmap 的键和值?

我目前有以下。

private Map<Boolean, List<String>> reverseMap(Map<String, Boolean> permissions) {
    List<String> allow = new ArrayList<String>();
    List<String> deny = new ArrayList<String>();
    Map<Boolean, List<String>> returnvalue = new HashMap<Boolean, List<String>>();

    for (Entry<String, Boolean> entry : permissions.entrySet()) {
        if(entry.getValue()) {
            allow.add(entry.getKey());
        } else {
            deny.add(entry.getKey());
        }
    }

    returnvalue.put(true, allow);
    returnvalue.put(false, deny);
    return returnvalue;
}

【问题讨论】:

  • 您真的需要来自布尔的地图吗?只有两个可能的键(真和假)。两个 Collection、一个拒绝列表和一个允许列表怎么样?
  • @Thilo - 不要忘记null :) 但是,是的,我同意。

标签: java list dictionary arraylist hashmap


【解决方案1】:

GuavaBiMap 已经提供了一种反转其键值对的方法。也许您可以将有问题的Map 的接口更改为BiMap,或者使用以下代码:

private BiMap<Boolean, String> reverseMap(Map<String, Boolean> permissions) {
   BiMap<String, Boolean> bimap = HashBiMap.create(permissions);
   return bimap.inverse();
}

【讨论】:

    【解决方案2】:

    您可以考虑使用GuavaMultimap 实现之一。例如:

    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;
    }
    

    【讨论】:

    • 正是我想要的,谢谢:D
    【解决方案3】:

    首先要注意的是,如果您的值仅是真或假,则您实际上并不需要反向映射。如果你有更广泛的价值观,这将是有意义的。

    获取具有特定值的条目的一种简单(但不是很优雅)的方法是:

    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;
    }
    

    如果您需要时不时地调用它,您会发现这不是很好。拥有两个不同的地图(直的和反向的)并向两者添加条目是有意义的。您不能使用双向映射,因为键和值之间没有 1:1 的关系。

    更新:以下解决方案不起作用。参见 cmets。 您还可以考虑使用 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));
      }
    }
    

    【讨论】:

    • 我认为TreeMap在另一个map中按值排序不是一个好主意——如果base map的内容发生变化,那么TreeMap中的树就会不一致,导致意想不到的结果。
    • 我的意思是使用 TreeMap 而不是最初的 HashMap,很抱歉造成混淆 ;-)
    • 如果 base 是您要插入的 TreeMap,那么在插入新事物时会出现空指针异常(因为 base.get(newKey) 将为空)。我认为您不能安全地保留按值排序的 TreeMap :(
    • 写一个合适的 compare() 方法留给读者作为家庭作业;-) 顺便说一下,这个 compare 方法是由 TreeMap 调用的,不会被任何东西调用。
    • 比较器将被 TreeMap 用于键查找,这将阻止 Map 正常工作。我认为您不能以这种方式使用 TreeMap - 请参阅 stackoverflow.com/questions/2864840/treemap-sort-by-value/…stackoverflow.com/questions/7465369/…
    【解决方案4】:

    我会做类似的事情(但如果你必须经常做这种事情,考虑 Guava),只是用 Set 替换 List(看起来更一致)并预填充 reversemap:

    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;
    }
    

    【讨论】:

      猜你喜欢
      • 2011-04-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-21
      • 2015-11-21
      • 1970-01-01
      • 2020-04-01
      • 1970-01-01
      相关资源
      最近更新 更多