Как отсортировать значения карты по ключу в 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