У меня есть такие значения внутри карты:
Map<Integer, String> map = new HashMap<Integer, String>();
map.put(1,"mark");
map.put(2,"1.1");
map.put(3,"google");
map.put(4,"12");
map.put(5,"2.2);
Мне нужно заказать эту карту, заказав как числа, так и строки.
Теперь я получаю следующее (как вы можете видеть, числа не «упорядочены», так как это String)
1.1
12
2.2
google
mark
Что я должен получить:
1.1
2.2
12
google
mark
Как мне это сделать? Я немного запутался.
сделать простой преобразователь, возвращающий Float.parse, если числовая строка, Float.MAX_VALUE
в противном случае, и использовать компаратор на его основе
Вы не можете заказать Map
по значению входа. SortedMap
например. TreeMap
позволяет упорядочить записи по ключу. Кажется, вы можете использовать неправильную структуру данных.
В вашем примере вы можете определить функцию, которая будет снисходительно анализировать double
и возвращать Double.NaN
вместо исключения:
private double lenientParseDouble(String s) {
try {
return Double.parseDouble(s);
} catch (NumberFormatException ex) {
return Double.NaN;
}
}
Согласно Double.compare()
документам:
Double.NaN
is considered by this method to be equal to itself and greater than all other double values (includingDouble.POSITIVE_INFINITY
).
а затем использовать его как часть цепочки Comparator
map.values().stream()
.sorted(Comparator.comparingDouble(this::lenientParseDouble).thenComparing(Function.identity()))
.forEach(System.out::println);
Спасибо чувак, работает. Я никогда не видел этот синтаксис. Мне нужно получить отсортированное значение (чтобы добавить их в список) вместо того, чтобы печатать их с помощью System.out? Спасибо
Если вам действительно нужна карта, вы можете использовать LinkedHashMap
, который отсортирован по порядку вставки. Для сравнения значений вы можете создать свой собственный компаратор:
Comparator<String> stringAndNumberComparator = (s1, s2) -> {
try {
return Double.valueOf(s1).compareTo(Double.valueOf(s2));
} catch (NumberFormatException e) {
return s1.compareTo(s2);
}
};
Теперь вы можете использовать java-поток, чтобы отсортировать набор записей вашей карты и собрать его обратно в LinkedHashMap
:
Map<Integer, String> sorted = map.entrySet().stream()
.sorted(Map.Entry.comparingByValue(stringAndNumberComparator))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (s1, s2) -> s1, LinkedHashMap::new));
В качестве альтернативы вы можете использовать компаратор, предоставленный в ответ от Кароль Доубеки с Map.Entry.comparingByValue()
.
Результат будет {2=1.1, 5=2.2, 4=12, 3=google, 1=mark}
;
Если вам просто нужен список ваших значений, вы можете просто использовать это:
List<String> sorted = map.values().stream()
.sorted(stringAndNumberComparator)
.collect(Collectors.toList());
Результат в этом случае будет [1.1, 2.2, 12, google, mark]
.
Спасибо маааааааааааан. Я попробовал это, и это работает. :) Когда я не могу использовать .compareTo() , потому что s1 или s2 имеют значение null, какое значение я должен вернуть, чтобы не «испортить» отсортированную карту?
@MDP Вы можете добавить нулевые проверки раньше. например if (s1 == null) return -1; if (s2 == null) return 1;
, но вы получите Exception
, используя Collectors.toMap()
. См. stackoverflow.com/q/24630963/9662601 для получения дополнительной информации об этом. Другим вариантом может быть фильтрация ненулевых значений до или замена их ненулевыми значениями по умолчанию.
Что вы имеете ввиду под заказом карты? (
HashMap
не заказывается). Можете ли вы показать свой код?