按值排序 Hashmap,然后按字母顺序排序

Sort Hashmap by value and then alphabetically

我正在创建一个词频程序,它可以很好地计算单词数。我正在使用哈希图来存储词频。我使用单词作为键,计数作为值。但是,我想先按词频对末尾的 hashMap 进行排序,然后按字母顺序键进行排序,如下所示:

it - 2
of - 2
the - 2
times- 2 
was - 2  
best- 1 
worst - 1 

我猜我需要一个自定义比较器,但我不知道如何构造它。请问,有什么建议吗?

鉴于您只需要执行一次这种排序,我建议您创建一个 Result 对象来保存您的 StringInteger 值并实现 Comparable(保持密钥相同)。当您需要对结果进行排序时,只需在 HashMap 上调用 values(),然后对它们进行排序。

Main.java

import java.util.*;

class Main
{
    public static void main (String[] args) throws java.lang.Exception
    {
        HashMap<String, Result> hm = new HashMap<String, Result>();
        addTo(hm, "to");
        addTo(hm, "be");
        addTo(hm, "or");
        addTo(hm, "not");
        addTo(hm, "to");
        addTo(hm, "be");

        List<Result> results = new ArrayList(hm.values());
        Collections.sort(results);
        for(Result result : results)
        {
            System.out.println(result.getValue() + " - " +result.getCount());
        }       
    }

    public static void addTo(HashMap<String, Result> hm, String entry)
    {
        if(! hm.containsKey(entry))
        {
            Result result = new Result(entry);
            hm.put(entry, new Result(entry));
        }
        hm.get(entry).increment();
    }
}

Result.java

public class Result implements Comparable
    {
        private int count;
        private String value;

        public Result(String value)
        {
            this.value = value;
            this.count = 0;
        }

        public String getValue()
        {
            return value;
        }

        public int getCount()
        {
            return count;
        }

        public void increment()
        {
            count++;
        }

        @Override
        public int compareTo(Object o)
        {
            Result result = (Result)o;
            if(getCount() == result.getCount())
            {
                return getValue().compareTo(result.getValue());
            }
            else
            {
                // Want larger values to be on-top, so reverse traditional sort order
                return ((Integer)result.getCount()).compareTo((Integer)getCount());
            }
        }
    }

您不能排序 HashMap,如 Javadoc:

中所述

... This class makes no guarantees as to the order of the map; in particular, it does not guarantee that the order will remain constant over time.

您必须将其放入一个不同的结构中,以保持您想要的顺序。

根据您提供的信息,您的订单似乎有几个标准:

  1. Map.Entry 降序排列
  2. Map.Entry升序排列

您可以使用 Stream API,以及 Map.Entry.

中有用的 Comparator
final HashMap<String, Integer> map = new HashMap<>();

map.put("it", 2);
map.put("of", 2);
map.put("the", 2);
map.put("times", 2);
map.put("was", 2);
map.put("best", 1);
map.put("worst", 1);

System.out.println("No Guaranteed Order:");
map.entrySet().stream()
        .forEach(System.out::println);


System.out.println();
System.out.println("With Ordering:");
map.entrySet().stream()
        .sorted(Map.Entry.<String, Integer>comparingByValue()
                        .reversed()
                .thenComparing(Map.Entry.comparingByKey()))
        .forEach(System.out::println);

输出:

No Guaranteed Order:
the=2
times=2
of=2
was=2
best=1
worst=1
it=2

With Ordering:
it=2
of=2
the=2
times=2
was=2
best=1
worst=1