如何在Java中按键对Map值进行排序?

时间:2009-05-28 18:43:06

标签: java dictionary hashmap

我有一个Map,它包含键和值的字符串。

数据如下:

  

“问题1”,“1”
  “问题9”,“1”
  “问题2”,“4”
  “问题5”,“2”

我想根据其键对地图进行排序。所以,最后,我将question1, question2, question3 ....等等。


最终,我试图从这个Map中获取两个字符串。

  • 第一个字符串:问题(按顺序为1.10)
  • 第二个字符串:答案(与问题的顺序相同)

现在我有以下内容:

Iterator it = paramMap.entrySet().iterator();
while (it.hasNext()) {
    Map.Entry pairs = (Map.Entry) it.next();
    questionAnswers += pairs.getKey() + ",";
}

这会在字符串中提出问题,但它们不合适。

18 个答案:

答案 0 :(得分:573)

简短回答

使用TreeMap。这正是它的用途。

如果此地图传递给您而您无法确定类型,则可以执行以下操作:

SortedSet<String> keys = new TreeSet<>(map.keySet());
for (String key : keys) { 
   String value = map.get(key);
   // do something
}

这将以按键的自然顺序遍历地图。


更长的答案

从技术上讲,您可以使用任何实现SortedMap的内容,但除极少数情况外,这相当于TreeMap,就像使用Map实施通常相当于HashMap一样。

如果你的密钥是一个没有实现Comparable的复杂类型,或者你不想使用自然顺序,那么TreeMapTreeSet会有额外的构造函数让你传入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());

使用TreeMapTreeSet时,请注意,它具有与HashMapHashSet不同的性能特征。粗略地说,找到或插入元素的操作将从 O(1)变为 O(Log(N))

HashMap中,从1000个项目移动到10,000个项目并不会影响您查找元素的时间,但对于TreeMap,查找时间将慢大约3倍(假设Log <子> 2 )。对于每个元素查找,从1000移动到100,000将大约慢6倍。

答案 1 :(得分:127)

假设TreeMap不适合你(假设你不能使用泛型):

List sortedKeys=new ArrayList(yourMap.keySet());
Collections.sort(sortedKeys);
// Do what you need with sortedKeys.

答案 2 :(得分:49)

使用TreeMap可以对地图进行排序。

Map<String, String> map = new HashMap<>();        
Map<String, String> treeMap = new TreeMap<>(map);
for (String str : treeMap.keySet()) {
    System.out.println(str);
}

答案 3 :(得分:34)

使用TreeMap

答案 4 :(得分:34)

如果您已经有了地图并希望在按键上进行排序,只需使用:

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

答案 5 :(得分:29)

只需使用TreeMap

new TreeMap<String, String>(unsortMap);

请注意,TreeMap会根据其键的自然顺序排序&#39;

答案 6 :(得分:12)

如果您无法使用TreeMap,在 Java 8 中,我们可以使用Collectors中的toMap()方法,其中包含以下参数:

  • keymapper :生成密钥的映射函数
  • valuemapper :映射函数以生成值
  • mergeFunction :一个合并函数,用于 解决与同一个键相关联的值之间的冲突
  • mapSupplier :一个返回一个新的空Map的函数 结果将被插入。

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));

答案 7 :(得分:7)

使用 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));

答案 8 :(得分:5)

此代码可以对两个订单中的键值映射进行排序,即升序和降序。

<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

答案 9 :(得分:5)

在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());

答案 10 :(得分:1)

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);
}

答案 11 :(得分:1)

使用 LinkedHashMap,它提供键排序。它还提供与 HashMap 相同的性能。它们都实现了 Map 接口,因此您只需将初始化对象 HashMap 替换为 LinkedHashMap

答案 12 :(得分:0)

我们也可以使用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 :(得分:0)

在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 :(得分:0)

功能样式如下所示:

 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);

输出:

  

question1

     

question2

     

question5

     

问题9

答案 15 :(得分:0)

以防万一您不想使用TreeMap

public static Map<Integer, Integer> sortByKey(Map<Integer, Integer> map) {
    List<Map.Entry<Integer, Integer>> list = new ArrayList<>(map.entrySet());
    list.sort(Comparator.comparingInt(Map.Entry::getKey));
    Map<Integer, Integer> sortedMap = new HashMap<>();
    list.forEach(e->map.put(e.getKey(), e.getValue()));
    return map;
}

另外,如果您想基于values对地图进行排序,只需将Map.Entry::getKey更改为Map.Entry::getValue

答案 16 :(得分:0)

提供了一个好的解决方案here。我们有一个HashMap,它以未指定的顺序存储值。我们定义一个辅助TreeMap,并使用putAll方法将所有数据从HashMap复制到TreeMap中。 TreeMap中的结果条目按键顺序排列。

答案 17 :(得分:0)

下面的树图怎么样:

Map<String, String> sortedMap = new TreeMap<>(Comparator.comparingInt(String::length)
.thenComparing(Function.identity()));

无论你在这个 sortedMap 中放入什么,它都会自动排序。 首先 TreeMapMap 接口的排序实现。 有一个但是,因为它在 [自然顺序方式][https://docs.oracle.com/javase/tutorial/collections/interfaces/order.html] 上对键进行排序。正如 Java 文档所说 String 类型是词典自然顺序类型。想象下面的字符串类型的数字列表。表示以下列表将按预期排序。

List<String> notSortedList = List.of("78","0", "24", "39", "4","53","32");

如果您只是使用默认的 TreeMap 构造函数,如下所示,并像下面一样逐个推送每个元素:

    Map<String, String> map = new TreeMap<>();
    for (String s : notSortedList) {
        map.put(s, s);
    }


    System.out.println(map);

输出为:{0=0, 14=14, 24=24, 32=32, 39=39, 4=4, 48=48, 53=53, 54=54, 78=78}

如您所见,数字 4 出现在“39”之后。这是 Lexicographic 数据类型(如 String)的本质。如果那个是整数数据类型,那没关系。

要修复这个使用参数,首先检查字符串的长度,然后比较它们。在 java 8 中是这样完成的:

Map<String, String> sortedMap = new TreeMap<>(Comparator.comparingInt(String::length)
.thenComparing(Function.identity()));

它首先按长度比较每个元素,然后将 compareTo 检查作为与要比较的元素相同的输入。

如果你更喜欢使用更容易理解的方法,上面的代码和下面的代码是等价的:

   Map<String, String> sortedMap = new TreeMap<>(
             new Comparator<String>() {
                @Override
                public int compare(String o1, String o2) {
                    int lengthDifference = o1.length() - o2.length();
                    if (lengthDifference != 0) return lengthDifference;
                    return o1.compareTo(o2);
                }
            }
    );

因为 TreeMap 构造函数接受比较器接口,所以您可以构建复合类的任何更复杂的实现。

这也是另一种形式更简化的版本。

    Map<String,String> sortedMap = new TreeMap<>(
           (Comparator<String>) (o1, o2) ->
            {
                int lengthDifference = o1.length() - o2.length();
                if (lengthDifference != 0) return lengthDifference;
                return o1.compareTo(o2);
            }
    );