При сортировке карты по значению некоторые значения отсутствуют. Чем вызвано такое странное поведение?
Я пытаюсь разобраться в карте на основе частоты употребления слов (т. е. на основе стоимости). Для этого я переопределил компаратор и перешел к 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);
}
}
Вывод:
Before sorting: {two=2, one=1, three=3, four=3}
After sorting based on value:{one=1, two=2, three=3}
Ожидаемый Результат:
{one=1, two=2, four=3,three=3}
3 ответа:
Ваш метод
compare
не подчиняется контракту интерфейса Map, так как он сравнивает значения вместо ключей. Ваша реализация приводит к тому, что два ключа с одинаковым значением считаются одним и тем же ключом. Поэтому вашsortedMap
не содержит ключа "четыре", который имеет то же значение, что и ключ" три".Обратите внимание, что порядок, поддерживаемый древовидной картой , как и любая сортированная карта, и независимо от того, предусмотрен ли явный компаратор, должен быть согласован с равными, если эта сортированная карта предназначена для правильной реализации интерфейса карты . (См. сопоставимые или компаратором для точного определения непротиворечивым с, равняется.) это так, потому что интерфейс карты определяется в терминах операции equals, но сортированная карта выполняет все ключевые сравнения, используя свой метод compareTo (или compare) , поэтому два ключа, которые считаются равными этим методом, с точки зрения отсортированной карты равны. Поведение отсортированной карты хорошо определено, даже если ее упорядочивание несовместимо с равными; оно просто не подчиняется общему контракту интерфейса карты.
Эту проблему можно решить, сравнив ключи, когда значения равны:
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); } } };
Это должно дать вам результат:
After sorting based on value:{one=1, two=2, four=3, three=3}
Так как
four<three
основано на естественном порядке строк.
Из-за вашего
compare()
стоит рассматривать значения только вMap
. Тогдаthree=3, four=3
имеет то же значение3
. Тогда те считают дубликатами, когда они добавляют кTreeMap
.
Это потому, что ваша реализация говорит TreeMap, что map[три] и map[четыре] по сути являются одним и тем же элементом, потому что они "равны" друг другу в соответствии с вашим компаратором.
Измените "return 0" в компараторе на " return 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}
(я думаю, вы можете понять, почему "четыре" в этом случае стоит перед "три")