在根据值对地图进行排序时,会丢失一些值.是什么导致这种奇怪的行为?

Sag*_*udi 6 java collections map treemap

我试图根据词频(即基于值)对地图进行排序.为此,我已经覆盖了比较器并传递给了TreeMap,但我得到了这个奇怪的输出.

public class WordFrequency {
    public static String sentence = "one three two two three three four four four";
    public static Map<String, Integer> map;

    public static void main(String[] args) {
        map = new HashMap<>();
        String[] words = sentence.split("\\s");

        for (String word : words) {
            Integer count = map.get(word);
            if (count == null) {
                count = 1;
            } else {
                ++count;
            }
            map.put(word, count);
        }

        Comparator<String> myComparator = new Comparator<String>() {

            @Override
            public int compare(String s1, String s2) {
                if (map.get(s1) < map.get(s2)) {
                    return -1;
                } else if (map.get(s1) > map.get(s2)) {
                    return 1;
                } else {
                    return 0;
                }
            }

        };
        SortedMap<String, Integer> sortedMap = new TreeMap<String, Integer>(myComparator);
        System.out.println("Before sorting: " + map);
        sortedMap.putAll(map);
        System.out.println("After Sorting based on value:" + sortedMap);

    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

Before sorting: {two=2, one=1, three=3, four=3}
After sorting based on value:{one=1, two=2, three=3}
Run Code Online (Sandbox Code Playgroud)

预期产出:

{one=1, two=2, four=3,three=3}
Run Code Online (Sandbox Code Playgroud)

Era*_*ran 5

您的compare方法无法遵守Map接口的约定,因为它比较值而不是键.您的实现会导致具有相同值的两个键被视为相同的键.因此,您sortedMap不包含"四"键,其值与"三"键相同.

请注意,如果此有序映射要正确实现Map接口,则树映射维护的顺序(如任何有序映射)以及是否提供显式比较器必须与equals一致.(见相当或比较为一致的精确定义与equals).这是因为Map接口是按照equals操作定义的,但有序映射使用它的compareTo执行所有的键比较(或比较)方法,因此2从排序映射的角度来看,通过此方法被视为相等的键是相等的.即使排序与equals不一致,也可以很好地定义有序映射的行为.它只是不遵守Map接口的一般合同.

TreeMap参考

您可以通过在值相等时比较键来解决此问题:

    Comparator<String> myComparator = new Comparator<String>() {

        @Override
        public int compare(String s1, String s2) {
            if (map.get(s1) < map.get(s2)) {
                return -1;
            } else if (map.get(s1) > map.get(s2)) {
                return 1;
            } else {
                return s1.compareTo(s2);
            }
        }

    };
Run Code Online (Sandbox Code Playgroud)

这应该给你一个输出:

After sorting based on value:{one=1, two=2, four=3, three=3}
Run Code Online (Sandbox Code Playgroud)

因为four<three基于字符串的自然顺序.