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

n00*_*kie 343 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() + ",";
}
Run Code Online (Sandbox Code Playgroud)

这让我得到一个字符串中的问题,但他们不是有序的.

Jhe*_*ico 586

简短的回答

用一个TreeMap.这正是它的用途.

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

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

这将按照键的自然顺序遍历地图.


更长的答案

从技术上讲,您可以使用任何实现的东西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());
Run Code Online (Sandbox Code Playgroud)

请记住,当使用TreeMapTreeSet具有不同于HashMap或的性能特征时HashSet.粗略地说,找到或插入元素的操作将从O(1)变为O(Log(N)).

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

  • CompareTo() 结果为 0 是“等于”。如果您正在编写一个按字符串长度排序的比较器,那么您需要根据哪个字符串较长返回正值或负值,并且仅当两个字符串长度相同时才返回 0。如果 a 和 b 是字符串,您可以像“return a.length() - b.length()”那样执行此操作(或者如果您希望它们按另一个方向排序,则反转值)。 (2认同)

Tra*_*Man 134

假设TreeMap对你不好(假设你不能使用泛型):

List sortedKeys=new ArrayList(yourMap.keySet());
Collections.sort(sortedKeys);
// Do what you need with sortedKeys.
Run Code Online (Sandbox Code Playgroud)

  • 谢谢!我需要做这样的事情因为我的钥匙是一个复杂的类型. (3认同)
  • 这只是对键列表进行排序,但不会根据键对地图本身进行排序.我也在寻找如何根据键对地图进行排序,并找到一种方法.我将不得不尝试使用TreeMap我猜:) (3认同)

小智 52

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

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


Agi*_*Jon 36

使用TreeMap!

  • +1 - 不够灵活,无法击败Jherico,Jon,但仍然相当不错.8) (30认同)

M-D*_*M-D 35

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

Map<String, String> treeMap = new TreeMap<String, String>(yourMap);
Run Code Online (Sandbox Code Playgroud)

一个完整的工作示例:

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
Run Code Online (Sandbox Code Playgroud)


小智 31

只需使用TreeMap

new TreeMap<String, String>(unsortMap);
Run Code Online (Sandbox Code Playgroud)

请注意,TreeMap根据其"键"的自然顺序进行排序


i_a*_*ero 14

如果您不能使用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));
Run Code Online (Sandbox Code Playgroud)

我们可以修改示例以使用自定义比较器并基于键进行排序:

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));
Run Code Online (Sandbox Code Playgroud)


Tar*_*nyk 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));
Run Code Online (Sandbox Code Playgroud)


小智 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;
}
Run Code Online (Sandbox Code Playgroud)

举个例子:

Map<Integer,Double> recommWarrVals = new HashMap<Integer,Double>();
recommWarrVals = sortByValues(recommWarrVals, 1);  // Ascending order
recommWarrVals = sortByValues(recommWarrVals,-1);  // Descending order
Run Code Online (Sandbox Code Playgroud)


Ole*_*hov 5

在Java 8中

Map<K, V>按键排序,请将键放入List<K>:

List<K> result = map.keySet().stream().sorted().collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

要按顺序排序Map<K, V>,请将条目放入List<Map.Entry<K, V>>:

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

最后但同样重要的是:以区域设置敏感的方式对字符串进行排序- 使用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());
Run Code Online (Sandbox Code Playgroud)