Есть ли способ (возможно, с помощью Google Collections) получить минимальное значение Map(Key, Double)
?
Традиционным способом мне пришлось бы сортировать карту по значениям и брать первое/последнее.
Есть ли способ (возможно, с помощью Google Collections) получить минимальное значение Map(Key, Double)
?
Традиционным способом мне пришлось бы сортировать карту по значениям и брать первое/последнее.
Вы можете использовать стандартный Collections#min()
для этого.
Map<String, Double> map = new HashMap<String, Double>();
map.put("1.1", 1.1);
map.put("0.1", 0.1);
map.put("2.1", 2.1);
Double min = Collections.min(map.values());
System.out.println(min); // 0.1
Обновление: поскольку вам также нужен ключ, я не вижу способов в Collections
или Google Collections2
API, поскольку Map
не является Collection
. Maps#filterEntries()
также не очень полезен, так как вы знаете фактический результат только в конце итерации.
Тогда самым простым решением будет следующее:
Entry<String, Double> min = null;
for (Entry<String, Double> entry : map.entrySet()) {
if (min == null || min.getValue() > entry.getValue()) {
min = entry;
}
}
System.out.println(min.getKey()); // 0.1
(нулевая проверка на min
оставлена в стороне)
List<SomeObject>
вместо него в сочетании с подходящим Comparator<SomeObject>
или, может быть, Comparable<SomeObject>
. SomeObject
, в свою очередь, может содержать исходный ключ карты и значение. Set<SomeObject>
тоже может подойти, только индекс посчитаете сами.
- person BalusC; 06.05.2010
Вы по-прежнему можете использовать Collections.min
с пользовательским Comparator
, чтобы получить Map.Entry
с меньшим значением:
Map<String, Double> map = new HashMap<String, Double>();
map.put("1.1", 1.1);
map.put("0.1", 0.1);
map.put("2.1", 2.1);
Entry<String, Double> min = Collections.min(map.entrySet(), new Comparator<Entry<String, Double>>() {
public int compare(Entry<String, Double> entry1, Entry<String, Double> entry2) {
return entry1.getValue().compareTo(entry2.getValue());
}
});
System.out.printf("%s: %f", min.getKey(), min.getValue()); // 0.1: 0.100000
С Java 8:
Entry<String, Double> min = Collections.min(map.entrySet(),
Comparator.comparing(Entry::getValue));
Однострочный Java8
Key key = Collections.min(map.entrySet(), Map.Entry.comparingByValue()).getKey()
Традиционным способом мне пришлось бы сортировать карту по значениям и брать первое/последнее. спасибо
Нет, ты бы не стал. Вам придется перебирать все значения и на каждом этапе сравнивать текущий элемент с наименьшим из виденных до сих пор. Это O(n) по сравнению с O(n*log(n)) для сортировки — потенциально огромная разница.
Кстати, именно так работает Collections.min()
.
Использование потоков Java 8:
return map
.entrySet()
.stream()
.sorted(Comparator.comparingDouble(Map.Entry::getValue))
.findFirst()
.map(Map.Entry::getValue);
Or
return map
.entrySet()
.stream()
.min(Comparator.comparingDouble(Map.Entry::getValue))
.map(Map.Entry::getValue);
Но если вы хотите сделать это несколько раз, обязательно посмотрите heap.
Я был бы склонен использовать Google Collections BiMap:
String minKey = HashBiMap.create(map).inverse().get(Collections.min(map.values()));
Или что-то в этом роде (не проверено).
В Java 8 мы можем легко получить:
Double minValue = map.entrySet().stream().min(Map.Entry.comparingByValue()).get().getValue();
Double maxValue = map.entrySet().stream().max(Map.Entry.comparingByValue()).get().getValue();
.get()
. Они создают 'Optional.get()' без предупреждения 'isPresent()'. Посетите эту страницу, чтобы найти более безопасные альтернативы.
- person spectrum; 02.02.2019
Чтобы сделать это эффективно, вы можете определить свою собственную структуру данных, чтобы она реализовывала интерфейс карты, но также позволяла эффективную операцию getMin().
Это можно сделать с помощью двух внутренних структур данных: карты и дерева (или структуры данных кучи). Каждый раз, когда добавляется новая пара (K,V), добавляйте их на карту, а также в дерево (как одну запись). Это дает время O(1) для операций get(Key) и время O(log n) для операций добавления, удаления и getMin.
Использование java 8 (и статический импорт). Мы можем сделать решение @superfav более аккуратным:
Map<String, Double> myMap;
String theKeyWithHighestValue = Collections.min(myMap.entrySet(), comparingDouble(Entry::getValue)).getKey()