为什么在遍历哈希图时会打印重复的键?[已结束]

Why are duplicate keys printed when I'm looping through the hashmap? [closed]

提问人:Akash 提问时间:11/2/2023 最后编辑:Mike 'Pomax' KamermansAkash 更新时间:11/2/2023 访问量:99

问:


想改进这个问题吗?通过编辑这篇文章添加详细信息并澄清问题。

22天前关闭。

我的代码有什么问题?我正在尝试打印密钥,但是当我打印时,我得到了重复的密钥。我的印象是,当我们向哈希图添加重复键时,它会替换以前的键。

我正在尝试打印数组中的所有重复元素。

public static void repeatingElements(int a[], int n) {
  HashMap<Integer, Integer> map = new HashMap<>();
  for (int i = 0; i < n; i++) {
    if (map.containsKey(a[i])) {
      map.put(a[i], map.get(a[i]) + 1);
    } else {
      map.put(a[i],1);
    }

    for (Map.Entry<Integer, Integer> entry: map.entrySet()) {
      if (entry.getValue()>1) {
        System.out.print(entry.getKey() + " ");
      }
    }
  }
}
  • 输入:{12, 10, 9, 45, 2, 10, 10, 45}
  • 预期输出:10 45
  • 我得到的输出:10 10 10 45
Java 数组 hashmap 键值

评论

0赞 Sören 11/2/2023
这是代码的工作版本还是非工作版本?
0赞 user85421 11/2/2023
(你也可以用它来查看地图的内容;更好的是,使用调试器来逐步检查代码并分析发生的情况)System.out.println(map);
0赞 Akash 11/2/2023
@user85421为造成的混乱道歉。更新了代码。此外,在打印地图时,我不会得到重复的键,只会更新与键关联的值。
0赞 Akash 11/2/2023
@Sören非工作代码。
3赞 Chaosfire 11/2/2023
将条目集迭代移到将值放入其中的循环之外 - 当前,您在放置数据的循环的每次迭代中打印地图的状态。

答:

0赞 MWB 11/2/2023 #1

难道不是您的打印循环在错误的位置的问题吗?

public static void repeatingElements(int a[], int n){
        HashMap<Integer, Integer> map = new HashMap<>();
        for(int i=0;i<n;i++){
            if(map.containsKey(a[i])){
                map.put(a[i], map.get(a[i]) + 1);
            }
            else {
                map.put(a[i],1);
            }
        }
        for(Map.Entry<Integer, Integer> entry: map.entrySet()){
            if(entry.getValue()>1){
                System.out.print(entry.getKey() + " ");
            }
        }
}
1赞 vsfDawg 11/2/2023 #2

您得到的输出是在 for 循环的每次迭代中发出 Map 状态的结果。

考虑每次迭代时 Map 的状态:

12: [{12:1}]  Output: 
10: [{12:1}, {10:1}] Output: 
 9: [{12:1}, {10:1}, {9:1}] Output: 
45: [{12:1}, {10:1}, {9:1}, {45:1}] Output: 
 2: [{12:1}, {10:1}, {9:1}, {45:1}, {2:1}] Output: 
10: [{12:1}, {10:2}, {9:1}, {45:1}, {2:1}] Output: 10
10: [{12:1}, {10:3}, {9:1}, {45:1}, {2:1}] Output: 10
45: [{12:1}, {10:3}, {9:1}, {45:2}, {2:1}] Output: 10 45

因此,总输出最终为:10 10 10 45

解决方案是在循环之后移动该状态输出。

public static void repeatingElements(int a[], int n){
  HashMap<Integer, Integer> map = new HashMap<>();
  for(int i=0;i<n;i++){
    if(map.containsKey(a[i])){
      map.put(a[i], map.get(a[i]) + 1);
    } else {
      map.put(a[i],1);
    }
  }
  for(Map.Entry<Integer, Integer> entry: map.entrySet()){
    if(entry.getValue()>1){
      System.out.print(entry.getKey() + " ");
    }
  }
}

    
0赞 WJS 11/2/2023 #3
  • 对于首次遇到的所有值,请输入默认值 1。重复的键将替换当前值。
  • 找到每个键时,其值将替换为当前值加 1。
  • 因此,在第一个循环结束时,您的地图看起来像这样,因为发生次数和发生次数。103452
2=1
9=1
10=3
12=1
45=2

现在,如果你把最后一个循环移到第一个循环之外,你会得到以下内容。

10 45

这是修改后的代码。

public static void repeatingElements(int a[], int n) {
    Map<Integer, Integer> map = new HashMap<>();
    for (int i = 0; i < n; i++) {
        if (map.containsKey(a[i])) {
            map.put(a[i], map.get(a[i]) + 1);
        } else {
            map.put(a[i], 1);
        }
    }

    for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
        if (entry.getValue() > 1) {
            System.out.print(entry.getKey() + " ");
        }
    }
}

如果您只想检测哪些项目是重复项,而不关心它们出现多少次,则可以使用集。

  • 如果该值在添加到集合时已经存在,则返回 false,因此将其添加到集合中。seendups
  • 由于不会保留重复项,因此继续添加现有值不会有任何区别。sets
public static void repeatingElements(int vals[]) {
     Set<Integer> seen = new HashSet<>();
     Set<Integer> dups = new HashSet<>();
     for(int val : vals) {
         if (!seen.add(val)) {
             dups.add(val);
         }
     }
     System.out.println(dups);
}

指纹

[10, 45]
0赞 Reilas 11/2/2023 #4

"...我的印象是,当我们向哈希图添加重复键时,它会替换以前的键。..."

没错,它用相同的“哈希码”替换了密钥
这是来自 OpenJDK 的源代码。

GitHub – java/util/HashMap.java – putVal

“为什么在我遍历哈希图时打印重复的键?...

。我正在尝试打印数组中的所有重复元素。..."

循环后打印值。

HashMap<Integer, Integer> map = new HashMap<>();
for(int i=0;i<n;i++){
    if(map.containsKey(a[i])){
        map.put(a[i], map.get(a[i]) + 1);
    }
    else {
        map.put(a[i],1);
    }
}
for(Map.Entry<Integer, Integer> entry: map.entrySet()){
    if(entry.getValue()>1){
        System.out.print(entry.getKey() + " ");
    }
}

作为参考,您可以使用 Map#compute 方法。

for(int i=0;i<n;i++)
    map.compute(a[i], (k, v) -> v == null ? 1 : ++v);

或者,Map#mergeInteger#sum 方法。

for(int i=0;i<n;i++)
    map.merge(a[i], 1, Integer::sum);

另一种方法是使用 Collections#frequency 方法和 Set

void repeatingElements(int a[]){
    List<Integer> list = IntStream.of(a).boxed().toList();
    new HashSet<>(list).forEach(
        x -> {
            if (Collections.frequency(list, x) > 1)
                System.out.print(x + " ");
        });
}

评论

0赞 WJS 11/2/2023
我假设您意识到,对于每次调用,它都会遍历集合中每个值的整个列表。Collections.frequency