在Java中,是否有一个对象的作用类似于用于存储和访问键/值对的Map,但是可以返回键的有序列表和值的有序列表,从而使键和值列表的顺序相同? br />
因此,按照代码解释,我正在寻找某种行为,就像我的虚拟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);
}


评论

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

此代码不是一个很好的示例,因为任何Map实现都将充当您的示例代码。已排序,已排序或未排序。

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

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

这应该命名为Java Sorted Map,因为Ordered Map有所不同-请参阅LinkedHashMap。

#1 楼

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

该接口具有以下方法:



keySet(),该方法返回一组按升序排列的键

values(),它按对应键的升序返回所有值的集合。

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

评论


例如:SortedMap map = new TreeMap <>();

–本
17年1月22日在22:11

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

– K. Gol
17年1月24日在8:01



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

–user5047085
19年1月29日在7:55

从Java 8 Doc。 LinkedHashMap,其迭代顺序是最后一次访问其条目的顺序

– TRiNE
19年5月15日在9:45



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

– rob
19年6月11日15:29



#2 楼


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


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

评论


并且为了节省读者再次检查的时间,因为很难通过测试进行验证,keySet()方法有效地返回了一个LinkedHashSet,它反映了put()调用的顺序。请注意,重复调用同一密钥的put()不会改变顺序,除非您事先删除了该密钥。

– Glenn Lawrence
2015年3月3日在3:29



@TRiNE引用链接文档中的内容:“ ...这通常是将密钥插入地图的顺序”。除非您使用特殊的构造函数要求“访问顺序”,否则迭代顺序始终为“插入顺序”

– Qw3ry
20-10-23在8:41

#3 楼

LinkedHashMap保持键的顺序。

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

评论


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

– ianaya89
15年1月6日,0:29

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

– T30
15年3月6日在11:15

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

–拉尔夫
2015年6月4日,11:31

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

– ArturŁysik
20-2-13在8:51

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

– TRiNE
20-2-14在9:07



#4 楼

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

评论


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

– CorayThan
13年11月6日在18:06

@CorayThan,在这种情况下,您可以对最佳答案进行投票,而不是对可能正确但并非最佳的其他人进行投票...

–布鲁诺·孔德
13年8月8日在17:43

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

– CorayThan
13年8月8日在18:08

#5 楼

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

它有三个最有用的实现:TreeMap,ImmutableSortedMap和ConcurrentSkipListMap。

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)


#6 楼

我认为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

#7 楼

从Java 6开始,还有TreeMap的非阻塞线程安全替代方法。
请参阅ConcurrentSkipListMap。

#8 楼

tl; dr

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


TreeMap
ConcurrentSkipListMap

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

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

详细信息

这是我制作的图形表格,显示了十个功能部件与Java 11捆绑在一起的Map实现。NavigableMap接口首先应该是SortedMap的接口。逻辑上应该删除SortedMap,但不能删除,因为某些第三方地图实现可能正在使用接口。

如您在此表中所见,只有两个类实现SortedMap / NavigableMap接口:


TreeMap
ConcurrentSkipListMap

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

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


LinkedHashMap类按其最初插入的顺序返回其条目。

EnumMap按定义键的枚举类的顺序返回条目。例如,哪个员工正在覆盖一周中的哪一天(Map< DayOfWeek , Person >)的地图使用Java内置的DayOfWeek枚举类。该枚举的定义是第一个星期一和最后一个星期日。因此,迭代器中的条目将以该顺序出现。

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



#9 楼

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

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


#10 楼

现代Java版本的Steffi Keran的答案
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);
    }
}