【问题标题】:How to swap arrayMap values and keys in Java如何在 Java 中交换 arrayMap 值和键
【发布时间】:2016-01-26 05:25:36
【问题描述】:

我在反转给定映射并将其反转的键和值存储到另一个映射中时遇到了一些麻烦。我有一个方法原型如下:

public static Map<String, Set<String>> reverse (Map <String, Set<String>> graph);

因此,如果我有有向图的示例键,则:

{c -> arraySet{f, e}}
{b -> d}
{a -> arraySet{c, b}} 
{d -> g}
{e -> d}
{f -> arraySet{g, d}}

我需要有效地反转此图,以便使用 d -> b 代替 b -> d。

我认为这对我来说就是交换原始图中的值和键并将它们添加到 reverseMap。我想我可以遍历图中给定键的每组值,然后将它们存储在一个列表中。

很遗憾,我在实施和思考时遇到了麻烦。我真的很感激朝着正确的方向轻推。

【问题讨论】:

  • 您可能对 Guava 的Multimaps 感兴趣。

标签: java map key-value


【解决方案1】:

这是使用Guava Multimaps 的实际、有效、最新的代码:

SetMultimap<Integer, Integer> graph = HashMultimap.create();
graph.put(1, 2); // add an edge from 1 to 2
SetMultimap<Integer, Integer> inverse = Multimaps.invertFrom(
  graph, HashMultimap.<Integer, Integer> create());

(披露:我为 Guava 做出了贡献。)

但是如果你不能使用第三方库,做这样的事情......

Map<Integer, Set<Integer>> g;
Map<Integer, Set<Integer>> gInverse = new HashMap<Integer, Set<Integer>>();
for (Map.Entry<Integer, Set<Integer>> gAdj : g.entrySet()) {
  Integer v = gAdj.getKey();
  for (Integer w : gAdj.getValue()) {
    Set<Integer> wInverseAdj = gInverse.get(w);
    if (wInverseAdj == null) {
      gInverse.put(w, wInverseAdj = new HashSet<Integer>());
    }
    wInverseAdj.add(v);
  }
}

或者,如果您可以使用 Java 8,请使用此...

map.entrySet().stream()
   .flatMap(entryKToVs -> entryKToVs.getValue().stream()
       .map(v -> new AbstractMap.SimpleEntry<>(entryKToVs.getKey(), str)))
   .collect(groupingBy(Map.Entry::getValue, mapping(Map.Entry::getKey, toList())))

【讨论】:

    【解决方案2】:

    伪代码,但接近真实。只需使用Multimap

    Multimap<String, String> ret = Multimaps.newSetMultimap();
    for (Entry<String, Set<String>> entry : graph) {
      for(String neighbor : entry.getValue()) {
        ret.addTo(neighbor, entry.getKey());
      }
    }
    

    【讨论】:

    • 喜欢利用优秀库的想法,这样您就不必解决已经解决的问题!
    • 您的文档链接已经过时了好几年,但为什么不直接使用Multimaps.invertFrom呢?
    【解决方案3】:

    您需要遍历地图中的条目,然后,由于这些值存储在一个集合中,因此您需要遍历该集合。您需要检查每个键的结果映射,并在键不存在时创建一个新集合。

    public static Map<String, Set<String>> reverse (Map <String, Set<String>> graph) {
        Map<String, Set<String>> result = new HashMap<String, Set<String>>();
        for (Map.Entry<String, Set<String>> graphEntry: graph.entrySet()) {
            for (String graphValue: graphEntry.getValue()) {
                Set<String> set = result.get(graphValue);
                if (set == null) {
                    set = new HashSet<String>();
                    result.put(graphValue, set);
                }
                set.add(graphEntry.getKey());
            }
        }
        return result;
    }
    

    【讨论】:

    • 如果您使用 Multimap 而不是 Map,这将变得更加清晰。
    • 当带有空检查的单个 get() 会给出相同的结果时,您还会进行 2 次查找(containsKey() 和 get())。使用 Multimap 可以消除这种情况。
    • 好点。清理了它,但留下答案以防他由于某种原因不能使用番石榴。
    • 这太棒了!我更喜欢这个解决方案而不是其他解决方案。虽然 Guava 很好,但我更喜欢这个实现。非常感谢:)
    【解决方案4】:

    我首先建议编写一个Graph 类,它抽象出底层的Map 数据结构。当然,这只是将实现推送到Graph接口,而不是直接处理Map接口。

    所以现在,坚持你的地图:

    Map<String, Set<String>> graph;
    Map<String, Set<String>> reverse;
    

    我建议使用Map.entrySet() 从您的graph 获取条目集。然后对于每个Map.Entry,检索每个的键和值。接下来,对于值Set 中的每个“顶点”,将键插入与顶点关联的Set

    如果我将其格式化为类似于 Java 代码而不是英文句子,这可能会更清楚。我希望你能得到基本的想法。当然,如果它适合您的项目限制,则最好使用预先制作和预先测试的解决方案。

    【讨论】:

    • 两张地图都是Map>,不是双射地图。
    • @FrankPavageau 啊……我误解了。 OP是反转图中的边,而不是反转数据结构的映射关系。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-11-21
    • 2012-06-14
    • 1970-01-01
    • 2014-03-12
    • 1970-01-01
    • 1970-01-01
    • 2018-06-28
    相关资源
    最近更新 更多