有没有一种方法在Java中创建一个保持插入顺序且不允许重复的List/Set?

4
什么是在Java中保持插入顺序、不允许重复并允许检索最后插入元素的最有效方法?

我假设你的意思是“插入顺序”,而不是元素总是有序。 - SLaks
2
什么顺序?自然顺序?插入顺序? - user395760
插入顺序。我已经更新了问题。 - Wayne
3个回答

10

尝试使用LinkedHashSet,它可以保持输入的顺序。

请注意,重新插入元素会更新其在输入顺序中的位置,因此您可能首先要检查元素是否已包含在集合中。

编辑:

您还可以尝试使用Apache commons collections类ListOrderedSet。如果我没有再次错读JavaDoc,它会按顺序装饰一个集合以保持插入顺序,并提供一个get(index)方法。

因此,似乎您可以通过使用new ListOrderedSet(new HashSet())来获得想要的结果;

不幸的是,这个类没有提供泛型参数,但它可能能帮助您入门。

编辑2:

这里有一个项目,它似乎使用泛型表示commons collections,即它有一个ListOrderedSet<E>,因此您可以例如调用new ListOrderedSet<String>(new HashSet<String>());


3
最后一部分是错误的。直接从JavaDoc中可以看到:"请注意,如果元素重新插入到集合中,插入顺序不会受到影响。" - Joachim Sauer
谢谢,这几乎是我想要的,但我注意到它没有get(index)方法。我需要一种检索最后插入的元素而不必遍历整个Set的方法。我已经更新了问题以反映这一点。 - Wayne
不幸的是,JRE没有带有实现List且不允许重复项的类。在这种情况下,您将不得不自己实现它(可能通过将List实现与Set实现结合起来)。 - Joachim Sauer
自Apache commons collections库的4.0版本起,ListOrderedSet现在支持泛型。 - Wesley Womack
关于那个被划掉的部分,提到了在添加最后一个元素时替换原始元素的重复元素。这里有一个问题实际上是要求这种行为:LinkedHashSet - insertion order and duplicates - keep newest "on top"。解决方案是子类化并覆盖LinkedHashSet::add方法。 - Basil Bourque

0

我认为JDK中没有任何东西可以做到这一点。

然而,LinkedHashMap作为LinkedHashSet的基础,接近实现了这个功能:它维护了一个循环双向链表来存储映射中的条目。它只跟踪列表的头部而不是尾部,但由于列表是循环的,header.before就是尾部(最近插入的元素)。

因此,您可以在此基础上实现您需要的内容。LinkedHashMap并未设计用于扩展,因此这有些棘手。您可以将代码复制到自己的类中并添加一个合适的last()方法(请注意许可问题),或者您可以扩展现有类,并添加一个使用反射获取私有headerbefore字段的方法。

这将会得到一个 Map,而不是 Set。然而,HashSet 已经是一个包装器,使得 Map 看起来像一个 Set。同样,它并不是为了一般的扩展而设计的,但你可以编写一个子类,其构造函数调用超类的构造函数,然后使用更多的反射来替换超类的 map 值为你的新 map 的实例。从那时起,该类应该完全符合你的要求。

顺便说一下,这里的库类都是由 Josh Bloch 和 Neal Gafter 编写的。这些人是 Java 的巨人之一。然而,那里的代码大部分都很糟糕。永远不要见你的英雄。


-1

只需使用{{link1:TreeSet}}。


3
这是一个有序的集合,而不是一个排序的集合(List 是有序的,而不是排序的)。 - Joachim Sauer
既然你能更好地看到差异,最好删除此答案,以免混淆他人。 - Mr_and_Mrs_D
一个集合只允许每个项目仅被插入一次,为了让所有可能阅读这个答案的人都清楚。 - Jakob Alexander Eichler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接