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


361

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

数据如下:

“ question1”,“ 1”
“ question9”,“ 1”
“ question2”,“ 4”
“ question5”,“ 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() + ",";
}

这使我的问题成串出现,但顺序不正确。

Answers:


612

简短答案

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

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

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

这将以键的自然顺序在地图上进行迭代。


更长的答案

从技术上讲,您可以使用任何实现的方法SortedMap,但是在极少数情况下TreeMapMap实现的费用与使用实现的费用通常相同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项增加到10,000项并不会真正影响您查找元素的时间,但是对于一个元素,TreeMap查找时间将慢3倍左右(假设Log 2)。对于每个元素查找,从1000迁移到100,000将慢6倍。


我正在尝试使用Treemap并根据长度对字符串键进行排序。我发现检索结果不一致。显然是因为TreeMap认为compareTo结果为0等于“等于”?不知道在这种情况下如何使用它。
Marc

1
compareTo()结果为0等于“等于”。如果要编写按字符串长度排序的比较器,则需要根据更长的字符串返回正或负值,并且如果两个字符串的长度相同,则仅返回0。如果a和b是字符串,则可以这样执行'return a.length()-b.length()'(或者如果希望它们在另一个方向上排序,则将它们取反)。
Jherico

嗨,大家好,如果他/她想通过按键来对Map进行排序(这里是1,2,3,4),那么插入顺序是什么....为什么不使用LinkedHashSet?我们只是将问题一一提出,并按插入的顺序对其进行排序。可以帮我这个忙吗?
Karoly 2015年

@Karoly LinkedHashSet将按您插入元素的顺序检索元素。OP想要的是以某种预定的排序顺序检索元素,而与插入顺序无关。
大卫·贝里

@ cricket_007,该代码专门演示了如何对尚未排序的地图的键进行迭代。
Jherico'3

137

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

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

3
谢谢!因为我的键是一个复杂的类型,所以我需要做这样的事情。
罗斯·汉布里克

3
这只会对键列表进行排序,而不会根据键对地图本身进行排序。我也在寻找如何根据键对地图进行排序,并找到一种方法。我猜我必须尝试使用​​TreeMap :)
Crenguta S'S

55

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

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

1
Map <String,List <String >> treeMap =新的TreeMap <String,List <String >>(printHashMap); for(String str:treeMap.keySet()){System.out.println(str +“” + treeMap.get(str)); }
vikramvi


36

如果您已经有了地图,并且想按键对它进行排序,则只需使用:

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

36

只需使用TreeMap

new TreeMap<String, String>(unsortMap);

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


19

如果您不能使用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));

仅适用于Api 24及更高版本的Android。
蒂娜

9

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

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

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

最后但并非最不重要的一点:以对语言环境敏感的方式对字符串进行排序-使用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());

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

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

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

这是按值而不是键排序。
raaj 2013年

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(sortedMap.put(e.getKey(), e.getValue()));
    return sortedMap;
}

另外,如果您想根据values更改Map.Entry::getKeyMap.Entry::getValue


这出现在我的评论日志中。有人试图用变量名修复一些错误(但失败了)。因此,我正确地修复了它们,但是,这个答案从根本上来说是错误的。将值添加到HashMap的顺序无关紧要。地图没有顺序。 stackoverflow.com/questions/10710193/...
aepryus
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.