简体   繁体   English

从 HashMap 中,如何删除 k 个具有最高值的元素(Java)?

[英]From a HashMap, how to remove k number of elements with the highest values(Java)?

myMap = {1=3, 2=2, 3=6, 4=8, 5=2, 6=1}

k = 3

so I'll delete the (3) highest map items with the highest values.所以我将删除具有最高值的 (3) 个最高的 map 项。

What can I do in Java so the map becomes?我可以在 Java 中做什么,这样 map 就变成了?

myMap = {2=2, 5=2, 6=1}

I tried a for loop that iterates (3) times我尝试了一个迭代 (3) 次的 for 循环

and within it, a nested for loop that uses map.entry to get the max value and remove it.在其中,嵌套的 for 循环使用 map.entry 获取最大值并将其删除。 I keep getting an error.我不断收到错误消息。


     int k =3; // number of large value pairs to remove

 int max = Collections.max(myMap.values()); // find max value
   

 for(int i =0; i<k ;i++) {  // iterate 3 times to delete (3) sets

    for (Map.Entry<Integer, Integer> entry : myMap.entrySet()) {
        Integer key = entry.getKey(); // find key associated with current largest value 
        Integer value = entry.getValue();// find largest value 
        if(value==max) { // test retrieved vale with max value 
            hMap.remove(key);// remove set from HashMap
        }
        max = Collections.max(myMap.values()); // find new maximum
    }      
 }

Error:错误:

Exception in thread "main" java.util.ConcurrentModificationException
    at java.base/java.util.HashMap$HashIterator.nextNode(HashMap.java:XXXX)
    at java.base/java.util.HashMap$EntryIterator.next(HashMap.java:XXXX)
    at java.base/java.util.HashMap$EntryIterator.next(HashMap.java:XXXX)

form jdk17 myMap.entrySet() -> hashMap's implements it will create a new EntryIterator() object,then will use super class HashIterator's constructors without arguments, When you use hashMap's put() or remove() method, modCount will + 1,As a result HashIterator's nextNode() enter image description here form jdk17 myMap.entrySet() -> hashMap's implements 它将创建一个新的 EntryIterator() object,然后将使用 super class HashIterator 的构造函数而不使用 arguments,当您使用 hashMap 的 put() 或 remove() 方法时,modCount 将 + 1,As结果 HashIterator 的 nextNode() enter image description here

There are multiple issues with your approach.您的方法存在多个问题。

  • It is very inefficient to loop through the values and keep finding the max after each delete遍历值并在每次删除后继续查找最大值是非常低效的
  • You are not allowed to modify the source map by calling the remove method from within the forEach loop of it's entry set.您不能通过从其条目集的 forEach 循环中调用 remove 方法来修改源 map。

Instead, get the keys corresponding to the top k values in your map and call the remove method on the map on each key, such as below..相反,获取与 map 中前k个值对应的键,并在每个键上调用 map 上的remove方法,如下所示。

Map<Integer, Integer> map = new HashMap<>(Map.of(1, 3, 2, 2, 3, 6, 4, 8, 5, 2, 6, 1));
int k = 3;

map.entrySet().stream().sorted((e1, e2) -> Integer.compare(e2.getValue(), e1.getValue())).map(e -> e.getKey())
            .limit(k).forEach(map::remove);

System.out.println(map);

prints: {2=2, 5=2, 6=1}打印:{2=2, 5=2, 6=1}

Using for(element e: list) loops uses the iterator of the map's entry set.使用for(element e: list)循环使用地图条目集的迭代器。 This iterator can only exist once at a time.这个迭代器一次只能存在一次。 The problem can be fixed by using a traditional for loop instead: for (int i = 0; i < myMap.entrySet().size(); i++) or similar.这个问题可以通过使用传统for循环来解决: for (int i = 0; i < myMap.entrySet().size(); i++)或类似的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM