如何在Java中按键排序映射值?

我有一个地图,有字符串的键和值。

数据如下所示:

" question ", " 1 ";
“问题9”,“1”;
“问题2”,“问题4”
“question5",“2“< / p >

我想根据键对映射进行排序。因此,在最后,我将有question1, question2, question3,等等。

最终,我试图从这个Map中得到两个字符串:

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

现在我有以下内容:

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

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

730611 次浏览

简短的回答

使用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,查找时间将会慢1.3倍(假设Log2)。从1000到100,000的每一个元素查找速度都要慢1.6倍。

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

List sortedKeys=new ArrayList(yourMap.keySet());
Collections.sort(sortedKeys);
// Do what you need with sortedKeys.
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);
}

我们也可以使用数组对键进行排序。排序方法。

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

使用TreeMap可以对映射进行排序。

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

如果你已经有了一个地图,想要按键排序,只需使用:

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

只需使用TreeMap:

new TreeMap<String, String>(unsortMap);

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

这段代码可以对键值映射进行两种排序,即升序和降序。

<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

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

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

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

最后但并非最不重要的:以地区敏感的方式对字符串进行排序-使用排序器 (comparator)类:

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

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

以防你不想使用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

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

使用LinkedHashMap,它提供键排序。它也提供了与HashMap相同的性能。它们都实现了Map接口,所以你可以将初始化对象HashMap替换为LinkedHashMap

使用下面的树形图:

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

无论您在sortedMap中放入什么,它都会自动排序。首先,TreeMapMap接口的排序实现。

有一个,因为它对自然秩序时尚中的键进行排序。正如Java文档所说,String类型是一个字典式的自然订单类型。想象一下下面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'之后。这是字典数据类型(如String)的本质。如果这个是整数数据类型,那么这是可以的。

要解决这个问题,请使用参数首先检查字符串的长度,然后比较它们。在Java 8中是这样做的:

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

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

如果你更喜欢使用一个更容易理解的方法,上面的代码将与下面的代码等效:

< p > Map<字符串,String>sortedMap = new TreeMap<>( 新的比较器(){ @Override (String o1, String o2) { int lengthDifference = o1.length() - o2.length(); if (lengthDifference != 0) 返回lengthDifference; 返回o1.compareTo (o2); } } < / p >);

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

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

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