简体   繁体   English

在Java中,我需要根据其值的基础对哈希映射的键进行分组

[英]In Java, I need to group the keys of a hash map based on the basis of their values

I need to find the topN keys. 我需要找到topN键。

I have an input as a HashMap in the form as (key : value): 我有一个输入作为HashMap的形式为(键:值):

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

I created a linked HapMap that is sorted based on values: 我创建了一个链接的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;
}

this gave my the output as: 这给了我的输出:

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

Now if I want to the Top-4 fruits, how should I approach if I want the output to be: 现在,如果我想要进入前4名成果,如果我想要输出,我应该如何处理:

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

I tried iterating through the sorted hashMap and compared the values of subsequent elements by doing 我尝试迭代排序的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++;
}

but this does not always work. 但这并不总是有效。

I am not able to think of a way around this. 我无法想到解决这个问题的方法。 Could someone please give me a lead? 有人可以请我带头吗?

You can use a two-step stream process - the first step groups the entries by the numeric value, the second sorts the stream contents, applies the limit of 4 and prints the result. 您可以使用两步流处理 - 第一步按数值对条目进行分组,第二步对流内容进行排序,应用限制为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(", "))));

This results in 这导致了

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

As I said in my comment, you will need to reverse your map first : so Map<String, Integer> will become Map<Integer, List<String>> . 正如我在评论中所说,您需要先反转地图:因此Map<String, Integer>将成为Map<Integer, List<String>>

Then, you can retrieve 4 max keys from your new map (formerly the values of your first map) and print their values 然后,您可以从新地图中检索4个最大键(以前是第一个地图的值)并打印它们的值

Map reverse method 映射反向方法

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;
}

How to use it 如何使用它

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()));

Here is the result 这是结果

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

Just iterate the HashMap and keep the first k elements. 只需迭代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;
}

You have to use a Map with the key-value pair (datatypes) reversed. 您必须使用具有反转键值对(数据类型)的Map Following is a basic implementation: 以下是一个基本实现:

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());
    });
}

Used TreeMap to keep it sorted as per key and used descendingMap() to print it in descending order. 使用TreeMap保持按键排序,并使用descendingMap()打印。

Output: 输出:

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

You can use SortedMap with a "Fruit" Object implementing Compareable. 您可以将SortedMap与实现Compareable的“Fruit”对象一起使用。

The map is ordered according to the natural ordering of its keys, or by a Comparator typically provided at sorted map creation time. 地图是根据其键的自然顺序排序的,或者是通常在排序地图创建时提供的比较器。 This order is reflected when iterating over the sorted map's collection views (returned by the entrySet, keySet and values methods). 迭代有序映射的集合视图(由entrySet,keySet和values方法返回)时会反映此顺序。 Several additional operations are provided to take advantage of the ordering. 提供了几个额外的操作以利用订购。 (This interface is the map analogue of SortedSet.) (此接口是SortedSet的地图模拟。)

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

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