416

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

数据如下:

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

我想根据它的键对地图进行排序。所以,最后,我会有question1, question2, question3……等等。


最终,我试图从这张地图中取出两个字符串。

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

现在我有以下内容:

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

这让我得到了一个字符串中的问题,但它们不是按顺序排列的。

4

17 回答 17

677

简短的回答

使用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有额外的构造函数允许您传入 a 的情况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());

请记住,当使用TreeMapor时TreeSet,它将具有与HashMapor不同的性能特征HashSet。粗略地说,查找或插入元素的操作将从O(1)变为O(Log(N))

在 aHashMap中,从 1000 个项目移动到 10,000 个并不会真正影响您查找元素的时间,但是对于 a 来说TreeMap,查找时间会慢 3 倍左右(假设 Log 2)。对于每个元素查找,从 1000 移动到 100,000 将慢大约 6 倍。

于 2009-05-28T18:43:59.257 回答
152

假设 TreeMap 对您不利(并假设您不能使用泛型):

List sortedKeys=new ArrayList(yourMap.keySet());
Collections.sort(sortedKeys);
// Do what you need with sortedKeys.
于 2009-05-28T19:03:21.807 回答
73

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

Map<String, String> map = new HashMap<>();        
Map<String, String> treeMap = new TreeMap<>(map);
for (String str : treeMap.keySet()) {
    System.out.println(str);
}
于 2011-11-07T11:51:32.767 回答
47

只需使用 TreeMap

new TreeMap<String, String>(unsortMap);

请注意,TreeMap 是根据其“键”的自然顺序排序的

于 2015-02-18T14:37:16.483 回答
40

使用树图

于 2009-05-28T18:44:43.187 回答
39

如果您已经有一张地图并想按键对其进行排序,只需使用:

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
于 2013-08-21T05:58:53.813 回答
27

如果你不能使用TreeMap,在Java 8中我们可以使用toMap()方法,Collectors该方法接受以下参数:

  • 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));
于 2016-11-17T08:21:07.343 回答
17

使用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));
于 2018-05-01T17:52:56.313 回答
14

在 Java 8 中

要按键排序 a Map<K, V>,将键放入 a List<K>

List<K> result = map.keySet().stream().sorted().collect(Collectors.toList());

要按键排序 a Map<K, V>,将条目放入 a List<Map.Entry<K, V>>

List<Map.Entry<K, V>> result =
    map.entrySet()
       .stream()
       .sorted(Map.Entry.comparingByKey())
       .collect(Collectors.toList());

最后但同样重要的是:以区域设置敏感的方式对字符串进行排序- 使用Collat​​or(比较器)类:

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());
于 2018-04-14T16:22:52.820 回答
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
于 2015-11-24T20:56:21.740 回答
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);
}
于 2011-11-07T11:34:21.320 回答
1

在 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);
    }
);
于 2018-02-06T16:26:41.123 回答
1

使用LinkedHashMap,它提供密钥排序。它也提供与HashMap. 它们都实现了Map接口,因此您只需将初始化对象替换HashMapLinkedHashMap.

于 2021-03-10T11:26:54.937 回答
1

以防万一你不想使用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 LinkedHashMap<>();
        list.forEach(e -> sortedMap.put(e.getKey(), e.getValue()));
        return sortedMap;
    }

此外,如果您想在values更改Map.Entry::getKey为的基础上对地图进行排序Map.Entry::getValue

于 2019-11-21T16:22:51.130 回答
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);
}
于 2011-11-07T11:37:36.467 回答
0

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

于 2020-09-08T16:30:04.630 回答
0

下面的树图怎么样:

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

无论你在这个 sortedMap 中放入什么,它都会自动排序。首先是接口TreeMap的排序实现。Map有一个但是因为它在 [自然顺序时尚] [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”之后。这是字典数据类型(如字符串)的本质。如果那个是整数数据类型,那也没关系。

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

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

它首先按长度比较每个元素,然后应用 check bycompareTo作为与要比较的元素相同的输入。

如果您更喜欢使用更易于理解的方法,上面的代码将等同于下面的代码:

   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);
            }
    );
于 2021-05-06T19:06:23.013 回答