【问题标题】:Removing Map Entry from inner For loop从内部 For 循环中删除 Map 条目
【发布时间】:2019-07-10 01:51:45
【问题描述】:

我在外循环和内循环中都使用了一个映射,我需要在内循环的映射中删除一个条目,以便删除的条目不再在外循环或内循环中迭代。

我在内部迭代器上尝试了 remove(),但是在外部循环上进一步迭代时确实会导致异常。

Map<String, String> testMap = new HashMap<>();
testMap.put("A", "AAA");
testMap.put("B", "BBB");
testMap.put("C", "CCC");
testMap.put("D", "DDD");

for(Iterator<Map.Entry<String, String>> it = testMap.entrySet().iterator(); it.hasNext();) {
    Map.Entry<String, String> outerEntry = it.next();
    for(Iterator<Map.Entry<String, String>> it1 = testMap.entrySet().iterator(); it1.hasNext();) {
        Map.Entry<String, String> innerEntry = it1.next();
        if(!outerEntry.getKey().equals(innerEntry.getKey()) && !innerEntry.getKey().equals("D")) {
            // it1.remove();
            // remove entries "B" and "C" from testMap so that the next iteration in outer loop is "D"
            // also I don't require the entries "B" and "C" in the inner loop once they are deleted
        }
    }
}

在给出的代码中,必须在外循环的第一次迭代时从 testMap 中删除条目“B”和“C”。外循环的下一个迭代器应该是“D”。

代码的目的是收集具有相同值的 Map 条目。

import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.util.Arrays;
import java.util.Set;
import java.util.HashSet;
import java.util.stream.Collectors;

public class Main {

    public static void main(String[] args)
    {
        Map<String, Map<String, List<String>>> resultMap = new HashMap<>();

        Map<String, List<String>> testMap = new HashMap<>();
        testMap.put("A", new ArrayList<>(Arrays.asList("AAA", "CCC", "BBB")));
        testMap.put("B", new ArrayList<>(Arrays.asList("AAA", "BBB", "CCC")));
        testMap.put("C", new ArrayList<>(Arrays.asList("CCC")));
        testMap.put("D", new ArrayList<>(Arrays.asList("DDD")));
        testMap.put("E", new ArrayList<>(Arrays.asList("DDD")));
        testMap.put("F", new ArrayList<>(Arrays.asList("AAA", "BBB", "CCC")));

        // process testMap in a way that resultMap contains
        // <A, <G1, [AAA, BBB, CCC]>>
        // <B, <G1, [AAA, BBB, CCC]>>
        // <C, <G2, [CCC]>>
        // <D, <G3, [DDD]>>
        // <E, <G3, [DDD]>>
        // <F, <G1, [AAA, BBB, CCC]>>

        // here G1, G2, G3 are groups that are created which represents testMap entries that have same values.
        // in resultMap, the order of [AAA, BBB, CCC] doesn't matter

        String gName = "G";
        int gId = 0;
        for(Map.Entry<String, List<String>> entry : testMap.entrySet()) {
            if (resultMap.containsKey(entry.getKey())) {
                continue;
            }
            ++gId;
            String group = gName + String.valueOf(gId);
            Set<String> entryValuesSet = new HashSet<>(entry.getValue());
            Map<String, List<String>> groupEntries = new HashMap<>();
            groupEntries.put(group, entry.getValue());

            Set<String> groupSet = testMap.entrySet().stream().filter(e -> !resultMap.containsKey(e.getKey()) && new HashSet(e.getValue()).equals(entryValuesSet)).map(f -> f.getKey()).collect(Collectors.toSet());
            // here is my problem.
            // Even though in the first iteration (entry "A") itself, entries "A", "B", "F" have assigned a group
            // they are still being checked on further iterations (entries "C", "D") and need a filter condition to exclude
            // which are really unnecessary checks if I could just delete those entries

            for (String g : groupSet) {
                resultMap.put(g, groupEntries);
            }
        }

        System.out.println(resultMap);
    }
}

有没有办法删除 testMap 中已经分配到组中的条目,从而避免不必要的检查?

【问题讨论】:

  • 当底层数据结构在迭代过程中被修改时,集合表现不佳。有几种方法可以解决这个问题。其中一个经典的方法是保留一个单独的要删除的对象列表,并在完成迭代后将它们全部删除。如果您解释代码的实际目标是什么,我敢打赌,有一种更简洁的方法可以完成它。因为我怀疑是否真的需要以这种方式精确地删除地图条目。
  • 嗨,乔丹。我已经提供了代码的实际目标。

标签: java for-loop hashmap iterator


【解决方案1】:

继@Jordans 评论之后:

您当前代码的问题是内部循环的第一次迭代删除了BC,然后外部循环预计接下来会遇到B,但这已被删除。

您可以通过使用列表来确定要删除的条目,类似于下面。

Map<String, String> testMap = new HashMap<>();
testMap.put("A", "AAA");
testMap.put("B", "BBB");
testMap.put("C", "CCC");
testMap.put("D", "DDD");

System.out.println(testMap);
List<Map.Entry<String, String>> removedInnerEntries = new ArrayList<>();
for(Map.Entry<String, String> outer : testMap.entrySet()){
     if(removedInnerEntries.contains(outer))
         continue;
     System.out.println("OuterLoop:" + outer);
     for(Map.Entry<String, String> inner : testMap.entrySet()) {
         System.out.println("InnerLoop:" + inner);
         if (!outer.getKey().equals(inner.getKey()) &&
                 !inner.getKey().equals("D") &&
                 !removedInnerEntries.contains(inner)) {
             System.out.println("  Remove :" + inner);
             removedInnerEntries.add(inner);
         }
    }
}
removedInnerEntries.forEach(e -> testMap.remove(e.getKey(), e.getValue()));
System.out.println(testMap);

但是,如果您运行它,您会注意到这并不完全正确,因为在最后一次迭代中 A 被删除,因为它不符合内部循环的第一个条件 !outer.getKey().equals(inner.getKey()),因此您还需要修复它.

或者,您可以创建自己的迭代器来执行此操作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-11-22
    • 2021-05-21
    • 2015-07-21
    • 1970-01-01
    • 1970-01-01
    • 2018-03-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多