Java有序 Map

Java中是否存在类似Map的对象,用于存储和访问键/值对,但可以返回键的有序列表和值的有序列表,这样键和值列表的顺序是相同的?

因此,作为代码解释,我正在寻找一些行为类似于我虚构的OrderedMap的东西:

OrderedMap om = new OrderedMap<>();
om.put(0, "Zero");
om.put(7, "Seven");


String o = om.get(7); // o is "Seven"
List keys = om.getKeys();
List values = om.getValues();


for(int i = 0; i < keys.size(); i++)
{
Integer key = keys.get(i);
String value = values.get(i);
Assert(om.get(key) == value);
}
406173 次浏览

是否存在一个类似Map的对象用于存储和访问键/值对,但可以返回键的有序列表和值的有序列表,这样键和值列表的顺序是相同的?

你正在寻找< >强java.util.LinkedHashMap < / >强。你会得到一个< >强Map.Entry< K, V> < / >强对的列表,它们总是以相同的顺序迭代。这个顺序和你放东西的顺序是一样的。或者,使用< >强java.util.SortedMap < / >强,其中键必须具有自然排序或由Comparator指定。

我认为你能从框架中得到的最接近的集合是SortedMap

SortedMap接口(带有实现TreeMap)应该是你的朋友。

接口有如下方法:

  • keySet()返回一组升序键
  • values()返回所有值的集合,按相应键的升序排列

所以这个接口完全满足了您的要求。但是,键必须有一个有意义的顺序。否则,可以使用LinkedHashMap,其中顺序由插入顺序决定。

我认为SortedMap接口强制执行您所要求的,而TreeMap实现了它。

http://java.sun.com/j2se/1.5.0/docs/api/java/util/SortedMap.html http://java.sun.com/j2se/1.5.0/docs/api/java/util/TreeMap.html < / p >

自Java 6以来,也有非阻塞的线程安全替代TreeMap。 看到ConcurrentSkipListMap。< / p >

可以利用NavigableMap接口,该接口可以按升序或降序键顺序访问和遍历。该接口是意图取代 SortedMap接口。Navigable map通常根据它的键的自然排序,或者由创建map时提供的Comparator进行排序。

它有三种最有用的实现:TreeMapImmutableSortedMapConcurrentSkipListMap

TreeMap例子:

TreeMap<String, Integer> users = new TreeMap<String, Integer>();
users.put("Bob", 1);
users.put("Alice", 2);
users.put("John", 3);


for (String key: users.keySet()) {
System.out.println(key + " (ID = "+ users.get(key) + ")");
}

输出:

Alice (ID = 2)
Bob (ID = 1)
John (ID = 3)

LinkedHashMap维护键的顺序。

否则,java.util.LinkedHashMap看起来就像正常的HashMap一样工作。

我已经使用简单的哈希映射,链表和集合来按值排序Map。

import java.util.*;
import java.util.Map.*;
public class Solution {


public static void main(String[] args) {
// create a simple hash map and insert some key-value pairs into it
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("Python", 3);
map.put("C", 0);
map.put("JavaScript", 4);
map.put("C++", 1);
map.put("Golang", 5);
map.put("Java", 2);
// Create a linked list from the above map entries
List<Entry<String, Integer>> list = new LinkedList<Entry<String, Integer>>(map.entrySet());
// sort the linked list using Collections.sort()
Collections.sort(list, new Comparator<Entry<String, Integer>>(){
@Override
public int compare(Entry<String, Integer> m1, Entry<String, Integer> m2) {
return m1.getValue().compareTo(m2.getValue());
}
});
for(Entry<String, Integer> value: list) {
System.out.println(value);
}
}
}

输出结果为:

C=0
C++=1
Java=2
Python=3
JavaScript=4
Golang=5

博士tl;

要保持Map< Integer , String >按键排序,可以使用实现SortedMap/NavigableMap接口的两个类之一:

或者第三方实现。可能在< em >谷歌番石榴< / em >Eclipse集合< em > < / em >中(我没有检查)。

如果在单个线程中操作映射,则使用第一个TreeMap。如果跨线程操作,则使用第二个ConcurrentSkipListMap

详细信息请参见下表和下面的讨论。

细节

下面是我制作的一个图形表,展示了与Java 11绑定的10个Map实现的特性。

NavigableMap接口是SortedMap的继承者。SortedMap逻辑上应该被删除,但不能被删除,因为一些第三方映射实现可能正在使用接口。

正如你在这个表中看到的,只有两个类实现了SortedMap/NavigableMap接口:

这两种方法都按顺序保存键,或按自然顺序(使用Comparable(https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Comparable.html)接口的compareTo方法),或通过传入的Comparator实现。这两个类的区别在于第二个类ConcurrentSkipListMap线程安全的,高度为并发

另请参阅下表中的迭代顺序列。

  • LinkedHashMap类按照它们在最初插入中的顺序返回它的项。
  • EnumMap 定义键的Enum类返回条目的顺序的。例如,某个员工在一周中的哪一天工作的映射(Map< DayOfWeek , Person >)使用Java中内置的DayOfWeek枚举类。该枚举定义为星期一的第一个和星期天的最后一个。所以迭代器中的条目会按照这个顺序出现。

其他六个实现没有承诺它们报告条目的顺序。

Table of map implementation in Java 11, comparison their features .

Steffi Keran回答的现代Java版本

public class Solution {
public static void main(String[] args) {
// create a simple hash map and insert some key-value pairs into it
Map<String, Integer> map = new HashMap<>();
map.put("Python", 3);
map.put("C", 0);
map.put("JavaScript", 4);
map.put("C++", 1);
map.put("Golang", 5);
map.put("Java", 2);
// Create a linked list from the above map entries
List<Map.Entry<String, Integer>> list = new LinkedList<>(map.entrySet());
// sort the linked list using Collections.sort()
list.sort(Comparator.comparing(Map.Entry::getValue));
list.forEach(System.out::println);
}
}