Java订购地图


322

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

因此,按照代码进行解释,我正在寻找某种行为,就像我的虚拟OrderedMap:

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

String o = om.get(7); // o is "Seven"
List<Integer> keys = om.getKeys();
List<String> 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);
}

4
如果您想要做的是同时遍历两个对象,则Map.entrySet()可以让您在任何地图上进行操作。LinkedHashMap具有明确定义的顺序,但是对于任何Map,条目集都会反映键/值对。
皮特·柯坎

5
此代码不是一个很好的示例,因为任何Map实现都将充当您的示例代码。排序,排序或不排序。
彼得·劳瑞

2
在Sun JDK实现中,由getKeys和getValues()集返回的集由映射中的entrySet()支持,因此将具有相同的迭代顺序,这就是您的示例所测试的。
皮特·柯坎

4
嗯,这很有趣,我从没注意到。还是让我发疯,但是我不希望对接口未进行明确验证的实现做一些假设。过去,我被这件事烧得太多了。
Whatsit

2
这应该命名为Java Sorted Map,因为Ordered Map有所不同-请参见LinkedHashMap
OndraŽižka2010年

Answers:


397

SortedMap的接口(与实施TreeMap的)应该是你的朋友。

该接口具有以下方法:

  • keySet() 它以升序返回一组键
  • values() 它以相应键的升序返回所有值的集合

因此,此接口完全可以满足您的要求。但是,密钥必须具有有意义的顺序。否则,您可以使用LinkedHashMap,其中顺序由插入顺序确定。


2
例如:SortedMap <String,Object> map = new TreeMap <>();

7
要使用TreeMap,它要求键类必须实现Comparable接口。如果不是,则将抛出某种RuntimeException。TreeMap也是排序后的地图,但我认为作者想使用仅排序(未排序)的地图。LinkedHashMap是仅获取有序映射的好选择(正如您所说的,“由插入顺序决定”)。
K. Gol

1
可以通过显示如何遍历keySet()来改善此答案

4
Java 8 docLinkedHashMap其迭代顺序是最后一次访问其条目
TRiNE

1
@TRiNE我没有听您的评论,但是我可能错过了一些背景信息。默认情况下LinkedHashMap,迭代顺序是插入顺序,但是您可以使用其他构造函数来指定访问顺序。docs.oracle.com/javase/8/docs/api/java/util/...

212

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

您正在寻找java.util.LinkedHashMap。您将获得Map.Entry <K,V>对的列表,该对始终以相同的顺序进行迭代。该顺序与放置项目的顺序相同。或者,使用java.util.SortedMap,其中键必须具有自然顺序或由来指定Comparator


14
而且,为了节省读者再次检查的时间,因为很难通过测试进行验证,该keySet()方法有效地返回了一个反映put()呼叫顺序的LinkedHashSet 。请注意,put()除非remove()事先输入密钥,否则重复调用同一密钥不会改变顺序。
Glenn Lawrence'3

Java 8 docLinkedHashMap其迭代顺序是最后一次访问其条目
TRiNE

24

LinkedHashMap维护键的顺序。

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


1
这不能为问题提供答案。要批评或要求作者澄清,请在其帖子下方留下评论-您可以随时对自己的帖子发表评论,一旦您拥有足够的声誉,就可以在任何帖子中发表评论
ianaya89 2015年

2
@ ianaya89我认为这是一个真实的答案,但这与John Feminella的答案非常相似!
T30 2015年

1
如果要获取有序地图,则将条目按放入地图时的顺序存储在其中,那么LinkedHashMap是正确的答案。如果要以独立于地图的形式对条目进行排序(按它们的放置顺序),那么SortedMap是正确的答案。
拉尔夫(Ralph)

@TRiNE您链接的Java 8文档说可能有两种排序模式:插入顺序和访问顺序。您可以考虑使用特殊的构造函数public LinkedHashMap(int initialCapacity,float loadFactor,boolean accessOrder)调用后者。默认构造函数创建一个按插入顺序排序的LinkedHashMap实例。
Artur Artysik 8:51

1
@ArturŁysik是的。几天前我做错了。我会改正的。我正在删除评论。因为我不再可以编辑它
TRiNE

7

我认为您从框架中获得的最接近的集合是SortedMap


3
如果我认为值得为此丢掉分数,我将投反对票。正如上面的答案所指出的那样,您的答案缺少有关LinkedHashMap的正确信息,对SortedMap的一些解释也是不错的。
CorayThan

@CorayThan,在这种情况下,您可以投票给最佳答案,而不是对其他可能正确但不是最好的答案投票……
bruno conde 2013年

1
那就是我所做的。只是说我能理解为什么有人会投反对票。
CorayThan

5

您可以利用可以按升序或降序键访问和遍历的NavigableMap接口。该接口旨在取代 SortedMap接口。通常,可导航地图是根据其键的自然顺序或在地图创建时提供的比较器进行排序的。

它有三个最有用的实现: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)



2

tl; dr

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

  • TreeMap
  • ConcurrentSkipListMap

如果要在单个线程中处理地图,请使用第一个TreeMap。如果要跨线程进行操作,请使用第二个ConcurrentSkipListMap

有关详细信息,请参见下表和以下讨论。

细节

这是我制作的图形表,显示了十个功能 Map与Java 11捆绑在一起实现。

NavigableMap接口是SortedMap应该首先使用的接口。的SortedMap逻辑上应该被删除,但不能作为某些第三方地图实现可以使用接口。

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

无论是在有序这些保持键,或者通过它们的自然顺序(使用compareTo的方法Comparablehttps://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/ Comparable.html)接口)或Comparator您通过的实现。这两个类之间的区别在于,第二个类ConcurrentSkipListMap线程安全的,高度并发的

另请参见下表中的“ 迭代顺序”列。

  • LinkedHashMap班由它们被顺序返回其条目最初插入
  • EnumMap定义键枚举类的顺序返回条目。例如,Map< DayOfWeek , Person >使用DayOfWeekJava内置的enum类的哪个员工正在覆盖星期几()的地图。该枚举的定义是第一个星期一和最后一个星期日。因此,迭代器中的条目将以该顺序出现。

其他六个实现不保证它们报告条目的顺序。

Java 11中的地图实现表,比较它们的功能


0

我使用了简单哈希映射,链接列表和集合来按值对映射进行排序。

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
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.