Как отсортировать значения карты по ключу в Java?
У меня есть карта, которая имеет строки для ключей и значений.
Данные похожи на следующее:
"question1", "1"
"question9", "1"
"question2", "4"
"question5", "2"
Я хочу отсортировать карту по ключам. Итак, в конце у меня будет question1, question2, question3
.... и так далее.
В конце концов, я пытаюсь получить две строки из этой карты.
- Первая строка: вопросы (в порядке 1.. 10)
- Вторая строка: ответы (в том же порядке, что и вопрос)
Прямо сейчас у меня есть следующее:
Iterator it = paramMap.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pairs = (Map.Entry) it.next();
questionAnswers += pairs.getKey() + ",";
}
Это дает мне вопросы в строке, но они не в порядке.
Ответы
Ответ 1
Короткий ответ
Используйте TreeMap
. Это именно то, для чего это.
Если эта карта передана вам, и вы не можете определить тип, то вы можете сделать следующее:
SortedSet<String> keys = new TreeSet<>(map.keySet());
for (String key : keys) {
String value = map.get(key);
// do something
}
Это будет проходить по карте в естественном порядке ключей.
Более длинный ответ
Технически, вы можете использовать все, что реализует SortedMap
, но за исключением редких случаев это равносильно TreeMap
, так же как использование реализации Map
обычно равносильно HashMap
.
Для случаев, когда ваши ключи являются сложным типом, который не реализует Comparable, или вы не хотите использовать естественный порядок, тогда TreeMap
и TreeSet
имеют дополнительные конструкторы, которые позволяют вам передавать Comparator
:
// placed inline for the demonstration, but doesn't have to be a lambda expression
Comparator<Foo> comparator = (Foo o1, Foo o2) -> {
...
}
SortedSet<Foo> keys = new TreeSet<>(comparator);
keys.addAll(map.keySet());
Помните, что при использовании TreeMap
или TreeSet
он будет иметь другие характеристики производительности, чем HashMap
или HashSet
. Грубо говоря, операции, которые находят или вставляют элемент, перейдут от O (1) к O (Log (N)).
В HashMap
переход от 1000 элементов к 10000 на самом деле не влияет на ваше время поиска элемента, но для TreeMap
время поиска будет примерно в 3 раза медленнее (при условии Log 2). Перемещение от 1000 до 100 000 будет примерно в 6 раз медленнее для каждого поиска элемента.
Ответ 2
Предполагая, что TreeMap не подходит для вас (и если вы не можете использовать generics):
List sortedKeys=new ArrayList(yourMap.keySet());
Collections.sort(sortedKeys);
// Do what you need with sortedKeys.
Ответ 3
С помощью TreeMap
вы можете отсортировать карту.
Map<String, String> map = new HashMap<>();
Map<String, String> treeMap = new TreeMap<>(map);
for (String str : treeMap.keySet()) {
System.out.println(str);
}
Ответ 4
Используйте TreeMap!
Ответ 5
Если у вас уже есть карта и вы хотите ее сортировать по клавишам, просто используйте:
Map<String, String> treeMap = new TreeMap<String, String>(yourMap);
Полный рабочий пример:
import java.util.HashMap;
import java.util.Set;
import java.util.Map;
import java.util.TreeMap;
import java.util.Iterator;
class SortOnKey {
public static void main(String[] args) {
HashMap<String,String> hm = new HashMap<String,String>();
hm.put("3","three");
hm.put("1","one");
hm.put("4","four");
hm.put("2","two");
printMap(hm);
Map<String, String> treeMap = new TreeMap<String, String>(hm);
printMap(treeMap);
}//main
public static void printMap(Map<String,String> map) {
Set s = map.entrySet();
Iterator it = s.iterator();
while ( it.hasNext() ) {
Map.Entry entry = (Map.Entry) it.next();
String key = (String) entry.getKey();
String value = (String) entry.getValue();
System.out.println(key + " => " + value);
}//while
System.out.println("========================");
}//printMap
}//class
Ответ 6
Просто используйте TreeMap
new TreeMap<String, String>(unsortMap);
Имейте в виду, что TreeMap сортируется в соответствии с естественным порядком его "ключей"
Ответ 7
При условии, что вы не можете использовать TreeMap
, в Java 8 мы можем использовать метод toMap() в Collectors
который принимает следующие параметры:
- keymapper: функция отображения для создания ключей
- valuemapper: функция отображения для получения значений
- mergeFunction: функция слияния, используемая для разрешения коллизий между значениями, связанными с одним и тем же ключом
- mapSupplier: функция, которая возвращает новую пустую карту, в которую будут вставлены результаты.
Пример Java 8
Map<String,String> sample = new HashMap<>(); // push some values to map
Map<String, String> newMapSortedByKey = sample.entrySet().stream()
.sorted(Map.Entry.<String,String>comparingByKey().reversed())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
Map<String, String> newMapSortedByValue = sample.entrySet().stream()
.sorted(Map.Entry.<String,String>comparingByValue().reversed())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1,e2) -> e1, LinkedHashMap::new));
Мы можем изменить пример для использования собственного компаратора и сортировки по ключам следующим образом:
Map<String, String> newMapSortedByKey = sample.entrySet().stream()
.sorted((e1,e2) -> e1.getKey().compareTo(e2.getKey()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1,e2) -> e1, LinkedHashMap::new));
Ответ 8
Используя Java 8:
Map<String, Integer> sortedMap = unsortMap.entrySet().stream()
.sorted(Map.Entry.comparingByKey())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
(oldValue, newValue) -> oldValue, LinkedHashMap::new));
Ответ 9
Этот код может сортировать карту значения ключа в обоих порядках, то есть восходящую и нисходящую.
<K, V extends Comparable<V>> Map<K, V> sortByValues
(final Map<K, V> map, int ascending)
{
Comparator<K> valueComparator = new Comparator<K>() {
private int ascending;
public int compare(K k1, K k2) {
int compare = map.get(k2).compareTo(map.get(k1));
if (compare == 0) return 1;
else return ascending*compare;
}
public Comparator<K> setParam(int ascending)
{
this.ascending = ascending;
return this;
}
}.setParam(ascending);
Map<K, V> sortedByValues = new TreeMap<K, V>(valueComparator);
sortedByValues.putAll(map);
return sortedByValues;
}
В качестве примера:
Map<Integer,Double> recommWarrVals = new HashMap<Integer,Double>();
recommWarrVals = sortByValues(recommWarrVals, 1); // Ascending order
recommWarrVals = sortByValues(recommWarrVals,-1); // Descending order
Ответ 10
В Java 8
Чтобы отсортировать Map<K, V>
по ключу, поместив ключи в List<K>
:
List<K> result = map.keySet().stream().sorted().collect(Collectors.toList());
Чтобы отсортировать Map<K, V>
по ключу, поместив записи в List<Map.Entry<K, V>>
:
List<Map.Entry<K, V>> result =
map.entrySet()
.stream()
.sorted(Map.Entry.comparingByKey())
.collect(Collectors.toList());
И последнее, но не менее важное: для сортировки строк с учетом языка - используйте класс Collator (компаратор):
Collator collator = Collator.getInstance(Locale.US);
collator.setStrength(Collator.PRIMARY); // case insensitive collator
List<Map.Entry<String, String>> result =
map.entrySet()
.stream()
.sorted(Map.Entry.comparingByKey(collator))
.collect(Collectors.toList());
Ответ 11
List<String> list = new ArrayList<String>();
Map<String, String> map = new HashMap<String, String>();
for (String str : map.keySet()) {
list.add(str);
}
Collections.sort(list);
for (String str : list) {
System.out.println(str);
}
Ответ 12
Мы также можем сортировать ключ с помощью метода Arrays.sort.
Map<String, String> map = new HashMap<String, String>();
Object[] objArr = new Object[map.size()];
for (int i = 0; i < map.size(); i++) {
objArr[i] = map.get(i);
}
Arrays.sort(objArr);
for (Object str : objArr) {
System.out.println(str);
}
Ответ 13
В Java 8 вы также можете использовать .stream(). Sorted():
myMap.keySet().stream().sorted().forEach(key -> {
String value = myMap.get(key);
System.out.println("key: " + key);
System.out.println("value: " + value);
}
);
Ответ 14
В функциональном стиле будет как ниже:
Map<String , String> nameMap = new HashMap<>();
nameMap.put("question1","1");
nameMap.put("question9","1");
nameMap.put("question2","4");
nameMap.put("question5","2");
nameMap.entrySet().stream()
.sorted(Comparator.comparing(x->x.getKey()))
.map(x->x.getKey())
.forEach(System.out::println);
Выход:
Вопрос 1
вопрос 2
Вопрос5
question9