简体   繁体   English

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

[英]While sorting the map based on value, some values are missing. What causes this weird behaviour?

I am trying to sort a map based on word frequency (ie, based on value). 我试图根据词频(即基于值)对地图进行排序。 For that I have overridden comparator and passed to TreeMap , but I am getting this weird output. 为此,我已经覆盖了比较器并传递给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);

    }
}

Output: 输出:

Before sorting: {two=2, one=1, three=3, four=3}
After sorting based on value:{one=1, two=2, three=3}

Expected Output: 预期产出:

{one=1, two=2, four=3,three=3}

Your compare method fails to obey the contract of the Map interface, since it compares values instead of keys. 您的compare方法无法遵守Map接口的约定,因为它比较值而不是键。 Your implementation causes two keys with the same value to be considered the same key. 您的实现会导致具有相同值的两个键被视为相同的键。 Therefore your sortedMap doesn't contain the "four" key, which has the same value as the "three" key. 因此,您的sortedMap不包含“四”键,其值与“三”键相同。

Note that the ordering maintained by a tree map , like any sorted map, and whether or not an explicit comparator is provided, must be consistent with equals if this sorted map is to correctly implement the Map interface . 请注意, 如果此有序映射要正确实现Map接口 ,则树映射维护的顺序 (如任何有序映射)以及是否提供显式比较器必须与equals一致 (See Comparable or Comparator for a precise definition of consistent with equals.) This is so because the Map interface is defined in terms of the equals operation, but a sorted map performs all key comparisons using its compareTo (or compare) method , so two keys that are deemed equal by this method are, from the standpoint of the sorted map, equal . (见相当或比较为一致的精确定义与equals)。 这是因为Map接口是按照equals操作定义的,但有序映射使用它的compareTo执行所有的键比较(或比较)方法 ,于是两个从排序映射的角度来看,通过此方法被视为相等的键是相等的 The behavior of a sorted map is well-defined even if its ordering is inconsistent with equals; 即使排序与equals不一致,也可以很好地定义有序映射的行为。 it just fails to obey the general contract of the Map interface. 它只是不遵守Map接口的一般合同。

TreeMap reference TreeMap参考

You can fix this problem by comparing the keys when the values are equal : 您可以通过在值相等时比较键来解决此问题:

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

    };

This should give you an output of : 这应该给你一个输出:

After sorting based on value:{one=1, two=2, four=3, three=3}

Since four<three based on the natural ordering of Strings. 由于four<three基于字符串的自然顺序。

Because of your compare() is consider values only in the Map . 因为你的compare()只考虑Map值。 Then three=3, four=3 has same value 3 . 然后three=3, four=3具有相同的值3 Then those consider as duplicates when they add to TreeMap . 然后,当它们添加到TreeMap时,它们会被视为重复项。

That's because your implementation is telling TreeMap that map[three] and map[four] are essentially the same element, because they are "equal" to each other according to your comparator. 那是因为你的实现告诉TreeMap map [three]和map [four]本质上是相同的元素,因为它们根据你的比较器彼此“相等”。

Change "return 0" in Comparator to "return s1.compareTo(s2)", and you'll have 将比较器中的“返回0”更改为“返回s1.compareTo(s2)”,您就可以了

Before sorting: {two=2, one=1, three=3, four=3}
After Sorting based on value:{one=1, two=2, four=3, three=3}

(I believe you can figure out why "four" comes before "three" in this case) (我相信你可以弄清楚为什么“四”在这种情况下出现在“三”之前)

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

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