【问题标题】:Reversing key value pairs in a HashMap反转 HashMap 中的键值对
【发布时间】:2017-03-30 01:44:33
【问题描述】:

我的数据结构如下:

Map<String,ArrayList<String>> graph = new HashMap<String,ArrayList<String>>();

这本质上是一个哈希映射,它将字符串值作为键并将字符串的数组列表存储在键的值中。 现在我正在尝试反转键值模式,使值成为键,键成为值。我的做法是这样的:

private Map<String,ArrayList<String>> reverseAdjList(Map<String,ArrayList<String>> adjList){
    Map<String,ArrayList<String>> tGraph = new HashMap<String,ArrayList<String>>();
    for (Map.Entry<String, ArrayList<String>> entry : adjList.entrySet()) {
        String key = entry.getKey();
        ArrayList<String> values = new ArrayList<>();
        values.add(key);
        ArrayList<String> value = entry.getValue();    
        for(String v:value){
            if(tGraph.containsKey(v)){
                values.addAll(tGraph.get(v));
            }
            tGraph.put(v, values);
        }
    }
    return tGraph;
}

所以这对我来说可以反转小数据集的哈希映射键值模式但是当我在更大的数据集上尝试它时遇到了

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:3210)
at java.util.Arrays.copyOf(Arrays.java:3181)
at java.util.ArrayList.grow(ArrayList.java:261)
at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:235)
at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:227)
at java.util.ArrayList.addAll(ArrayList.java:579)
at GraphProcessor.reverseAdjList(GraphProcessor.java:67)
at GraphProcessor.SCC(GraphProcessor.java:135)
at GraphProcessor.<init>(GraphProcessor.java:50)
at GraphProcessor.main(GraphProcessor.java:250)

我知道这是一种非常幼稚和错误的做法,有什么更好和正确的做法呢?

【问题讨论】:

  • 您的数据集有多大?也许您只需要使用 -Xmx 增加您的 jvm 堆大小
  • 您的代码错误。 values 每个键仅实例化一次,并且每个值都呈指数增长。尝试将 ArrayList&lt;String&gt; values = new ArrayList&lt;&gt;(); 移动到内部 for 循环。更好的是,将key 添加到先前映射的列表中,而不是每次都复制。
  • 太棒了!非常感谢你修复它。也感谢使用密钥的建议。
  • 抱歉,我通过尝试您的代码并将其发布为答案发现了您的错误,但 shmosel 已对其进行了评论,答案中还有一些重构的想法,所以我决定保留它,希望对您有所帮助。
  • 没问题,非常感谢您尝试帮助我@shizhz。非常感谢你,我发现你的回答真的很有帮助,而且解释得很好。

标签: java arraylist hashmap


【解决方案1】:

您的代码中有一个错误:

for (Map.Entry<String, ArrayList<String>> entry : adjList.entrySet()) {
    String key = entry.getKey();
    ArrayList<String> values = new ArrayList<>(); // Wrong place for this variable.
    values.add(key);
    ArrayList<String> value = entry.getValue();    
    for(String v:value){
        if(tGraph.containsKey(v)){
            values.addAll(tGraph.get(v));
        }
        tGraph.put(v, values);
    }
}

局部变量 values 应该在嵌套的 for 循环中,否则 values 会为所有以后的新键 v 累积,并且如果您的数据集很大,则会占用大量内存,它应该是:

private Map<String, ArrayList<String>> reverseAdjList(Map<String, List<String>> adjList) {
    Map<String, ArrayList<String>> tGraph = new HashMap<>();
    for (Map.Entry<String, List<String>> entry : adjList.entrySet())  {
        String key = entry.getKey();
        List<String> value = entry.getValue();
        for (String v : value) {
            ArrayList<String> values = new ArrayList<>();
            values.add(key);
            if (tGraph.containsKey(v)) {
                values.addAll(tGraph.get(v));
            }
            tGraph.put(v, values);
        }
    }
    return tGraph;
}

但实际上您不需要为每个内部for 步骤创建一个新的 List 实例,请在 JDK 1.8 中尝试以下代码:

private  Map<String, List<String>> reverseMap(Map<String, List<String>> adjList) {
    Map<String, List<String>> tGraph = new HashMap<>();
    for (Map.Entry<String, List<String>> entry : adjList.entrySet()) {
        for (String value : entry.getValue()) {
            tGraph.computeIfAbsent(value, v -> new ArrayList<>()).add(entry.getKey()); // Updated according comment from @shmosel
        }
    }
    return tGraph;
}

如果你使用的是旧版本的 jdk,你可以试试:

    private Map<String, List<String>> reverseMap(Map<String, List<String>> adjList) {
    Map<String, List<String>> tGraph = new HashMap<>();
    for (Map.Entry<String, List<String>> entry : adjList.entrySet()) {
        for (String value : entry.getValue()) {
            List<String> newValues = tGraph.get(value);
            if (newValues == null) {
                newValues = new ArrayList<>();
                tGraph.put(value, newValues);
            }
            newValues.add(entry.getKey());
        }
    }
    return tGraph;
}

希望这会有所帮助:-)

【讨论】:

  • 非常感谢!这非常有帮助。
  • @smriti 很高兴为您提供帮助 :-)
  • Java 8 中更好的解决方案:tGraph.computeIfAbsent(value, v -&gt; new ArrayList&lt;&gt;()).add(entry.getKey());
  • @shmosel,这真的很酷,非常感谢。我已经更新了答案:)
猜你喜欢
  • 2013-09-04
  • 1970-01-01
  • 2021-09-04
  • 2013-12-02
  • 2013-12-23
  • 1970-01-01
  • 2021-03-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多