【问题标题】:In Java, I need to group the keys of a hash map based on the basis of their values在 Java 中,我需要根据值对哈希映射的键进行分组
【发布时间】:2016-11-05 22:04:18
【问题描述】:

我需要找到前 N 个键。

我有一个 HashMap 的输入,格式为 (key : value):

Banana : 13  
Apple: 12  
Mango : 32  
Orange : 12  
Grape : 18  
Pear : 12  
Peach : 18  

我创建了一个基于值排序的链接 HapMap:

private static <K extends Comparable, V extends Comparable> Map<K, V> sortByValues(Map<K, V> map) {
    List<Map.Entry<K, V>> entries = new LinkedList<Map.Entry<K, V>>(map.entrySet());

    Collections.sort(entries, new Comparator<Map.Entry<K, V>>() {

        @Override
        public int compare(Map.Entry<K, V> o1, Map.Entry<K, V> o2) {
            return o2.getValue().compareTo(o1.getValue());
        }
    });
    Map<K, V> sortedMap = new LinkedHashMap<K, V>();
    for (Map.Entry<K, V> entry : entries) {
        sortedMap.put(entry.getKey(), entry.getValue());
    }
    return sortedMap;
}

这给了我的输出:

Mango : 32  
Grape : 18  
Peach : 18  
Banana : 13  
Apple: 12  
Orange : 12  
Pear : 12  

现在,如果我想要 Top-4 水果,如果我希望输出是:

Mango :32  
Grape, Peach : 18  
Banana :13  
Apple, Orange, Pear: 12  

我尝试遍历排序后的 hashMap 并比较后续元素的值

int sizeOfMap = myValueSortedMap.size();
ArrayList<String> keyArr = new ArrayList<String>();
int cnt=0,keyVal=0;

while(cnt<(sizeOfMap-1)){

    if(myValueSortedMap.values().toArray()[cnt] == myValueSortedMap.values().toArray()[cnt+1]){

        keyArr.add((String) myValueSortedMap.keySet().toArray()[cnt]+ " , " +(String) myValueSortedMap.keySet().toArray()[cnt+1]);
    }
    else{
        keyArr.add((String) myValueSortedMap.keySet().toArray()[cnt]);
        keyVal = (int) myValueSortedMap.values().toArray()[cnt];
    }
    cnt++;
}

但这并不总是有效。

我想不出办法解决这个问题。有人可以给我一个领导吗?

【问题讨论】:

  • 您可以尝试反转您的地图。新映射键将是来自第一个映射的 number 值,新映射值将是具有该值的第一个映射键的 list

标签: java sorting arraylist grouping top-n


【解决方案1】:

只需迭代 HashMap 并保留第一个 k 元素。

private HashMap<String, Integer> select_k_element(HashMap sortedMap,int k){
    HashMap<String, Integer> res=new HashMap();
    int i=0;
    for (Map.Entry<String, Integer> e : sortedMap.entrySet()) {
        String key=e.getKey();
        int value=e.getValue();
        res.put(key,value);
        i++;
        if(i>=k)
            break;
    }
    return res;
}

【讨论】:

    【解决方案2】:

    您必须使用 Map 并反转键值对(数据类型)。下面是一个基本的实现:

    private static Map<String, Integer> fruits = new HashMap<>();
    
    static {
        fruits.put("Banana",13);  
        fruits.put("Apple", 12);
        fruits.put("Mango",32);
        fruits.put("Orange",12); 
        fruits.put("Grape",18);
        fruits.put("Pear",12);
        fruits.put("Peach",18); 
    }
    
    public static void main(String[] args) {
        TreeMap<Integer, String> freq = new TreeMap<>();
    
        // Populate the new Map
        fruits.entrySet().forEach(e -> {
            Integer key = e.getValue();
            if(freq.containsKey(key)) { // Update entry if key is already present
                String curVal = freq.get(key);
                String newVal = e.getKey();
    
                freq.put(key, curVal + ", " + newVal);
            } else { // Add an entry if key is not present
                freq.put(key, e.getKey());
            }
        });
    
        // Print the new Map
        freq.descendingMap().entrySet().forEach(e -> {
            System.out.println(e.getValue() + " : " + e.getKey());
        });
    }
    

    使用TreeMap 保持按键排序,使用descendingMap() 以降序打印。

    输出:

    Mango : 32
    Grape,Peach : 18
    Banana : 13
    Apple,Pear,Orange : 12
    

    【讨论】:

      【解决方案3】:

      正如我在评论中所说,您需要先反转您的地图:所以Map&lt;String, Integer&gt; 将变为Map&lt;Integer, List&lt;String&gt;&gt;

      然后,您可以从新地图中检索最多 4 个键(以前是您的第一个地图的值)并打印它们的值

      地图反向法

      public static <K extends Comparable, V extends Comparable> Map<V, List<K>> reverseMap(Map<K, V> map) {
          Map<V, List<K>> result = new HashMap<>();
          map.entrySet().stream().forEach((entry) -> {
              List<K> lst = result.get(entry.getValue());
              if (lst == null) {
                  lst = new ArrayList<>();
                  result.put(entry.getValue(), lst);
              }
              lst.add(entry.getKey());
          });
          return result;
      }
      

      如何使用

      Map<String, Integer> map = new HashMap<>();
      map.put("Banana", 13);
      map.put("Apple", 12);
      map.put("Mango", 32);
      map.put("Orange", 12);
      map.put("Grape", 18);
      map.put("Pear", 12);
      map.put("Peach", 18); 
      
      Map<Integer, List<String>> flip = reverseMap(map);
      
      flip.entrySet().stream()
                  .sorted(Map.Entry.<Integer, List<String>>comparingByKey().reversed())
                  .limit(4)
                  .forEach(e -> System.out.println(String.join(", ", e.getValue()) + " : " + e.getKey()));
      

      这是结果

      Mango : 32
      Grape, Peach : 18
      Banana : 13
      Apple, Pear, Orange : 12
      

      【讨论】:

        【解决方案4】:

        您可以使用两步流式处理 - 第一步按数值对条目进行分组,第二步对流内容进行排序,应用 4 的限制并打印结果。

        map.entrySet()
           .stream()
           .collect(Collectors.groupingBy(Map.Entry::getValue))
           // the map now contains integers mapped to a list of map entries
           .entrySet()
           .stream()
           // sort the stream by descending numeric value
           .sorted((o1, o2) -> o2.getKey().compareTo(o1.getKey()))
           // use the first four elements of the stream
           .limit(4)
           .forEach(entry -> System.out.println(entry.getKey() + " " + entry.getValue().stream().map(Map.Entry::getKey).collect(Collectors.joining(", "))));
        

        这会导致

        32 Mango
        18 Grape, Peach
        13 Banana
        12 Apple, Pear, Orange
        

        【讨论】:

          【解决方案5】:

          您可以将SortedMap 与实现Compareable 的“水果”对象一起使用。

          地图根据其键的自然顺序进行排序,或者由通常在排序地图创建时提供的比较器进行排序。此顺序在遍历已排序地图的集合视图(由 entrySet、keySet 和 values 方法返回)时反映出来。提供了几个额外的操作来利用排序。 (这个接口是SortedSet的map类比。)

          【讨论】:

          • SortedMap&lt;String, Integer&gt; map = new TreeMap&lt;&gt;(); - 或者在 javadoc 中查看 SortedMap 的实现类。并遍历 entrySet。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2014-05-13
          • 2021-12-08
          • 2014-09-16
          • 2021-06-11
          • 2020-04-29
          • 2011-08-14
          • 2011-05-26
          相关资源
          最近更新 更多