如何在HashSet中保留插入顺序?

时间:2018-07-02 08:32:16

标签: java set

我写了以下代码,

public int longestConsecutive(int[] nums) {
Set<Integer> num_set = new HashSet<Integer>();
for (int num : nums) {
    num_set.add(num);
    System.out.println("num_set: " + num_set.toString());
}

然后我有测试用例,

int[] nums  = {100, 4, 200, 1, 3, 2};

然后在最后一行输出中,控制台显示

num_set: [1, 2, 3, 100, 4, 200]

我想知道为什么添加操作后更改了先前的顺序。

3 个答案:

答案 0 :(得分:7)

统计HashSet文档

  

对于集合的迭代顺序,它保证;特别是,它不能保证订单会在一段时间内保持不变。

如果要使用保持自然顺序的Set,请改用SortedSet

  

一个Set,进一步提供其元素的总体排序。元素使用其自然顺序或通过通常在排序集创建时提供的Comparator进行排序。

编辑: Set确实没有说任何有关其元素顺序的信息。例如,如果两个Set包含相同的元素并且具有相同的大小,则两个Set相等。 Set的迭代顺序取决于实现方式,并且在版本之间可能会有所不同,因此您不应对此做任何假设。它可能取决于#hashCode的值,但也可能取决于插入顺序或将来的其他操作。但是,我们不在乎,因为如果您这样做,则应该改用ListSortedSet

答案 1 :(得分:1)

格兰斯已经回答了您的问题。我仍然想添加一些内容:Java库中有接口,可为开发人员提供合同,并保证可以以哪种方式使用它们。

就像您的问题一样,基本界面Set

  

不包含重复元素的集合。

您的implementor HashSet(已经明确说明了不能保证订购的事实),在这种情况下,您应该不要与订单有关的承诺。

  

对于集合的迭代 order ,它没有没有保证;特别是,它不能保证顺序会随着时间的推移保持恒定。

具体地说,Java提供了另一个接口SortedSet来确保您要订购

  

一个Set,进一步提供其元素的总体排序。元素使用其自然顺序或通过通常在排序集创建时提供的Comparator进行排序。

因此,在您的情况下,您应该找到一个实现接口 implementor的{​​{1}},例如TreeSet

通常我们不太关心实现细节,因为可以在不知情的情况下对其进行调整/更改,而另一方面,承诺是库开发人员在官方文档将始终保留。

答案 2 :(得分:0)

您似乎想保留插入顺序。为此有一个名为LinkedHashSet的类。这是为您提供的一些示例代码:

int[] nums  = {100, 4, 200, 1, 3, 2};
Set<Integer> ints = new LinkedHashSet<>();
for(int i : nums) {
    ints.add(i);
}
System.out.println(ints);

上面的代码显示:[100, 4, 200, 1, 3, 2]

正如documentation所说:

  

Set接口的哈希表和链表实现,具有可预测的迭代顺序。此实现与HashSet的不同之处在于,它维护贯穿其所有条目的双向链接列表。此链接列表定义了迭代顺序,即将元素插入集合(插入顺序)的顺序。请注意,如果将元素重新插入到集合中,则插入顺序不会受到影响。 (如果在调用s.contains(e)之前立即返回true的情况下调用s.add(e),则将元素e重新插入到set s中。)