在Java标准库中没有专门用于此目的的集合类。但是,LinkedHashSet<E>
可以保留元素添加顺序,类似于 List
,因此,如果你将其包装在一个 List
中使用,则可以获得所需的语义。
另外,Commons Collections(或者通用版本的 commons-collections4
)已经有了符合你要求的 List
:SetUniqueList
/ SetUniqueList<E>
。
这是我做的,它可行。
假设我有一个ArrayList
,我所做的第一件事是创建一个新的LinkedHashSet
。
LinkedHashSet<E> hashSet = new LinkedHashSet<E>()
然后我尝试将我的新元素添加到LinkedHashSet
中。如果新元素是重复的,add
方法不会改变LinkedHasSet
并返回false。这就成为了我在添加到ArrayList
之前可以测试的一个条件。
if (hashSet.add(E)) arrayList.add(E);
这是一种简单而优雅的方法,用于防止重复项被添加到数组列表中。如果您愿意,可以将其封装在扩展 ArrayList
类的类的 add
方法中。只需记得通过循环遍历元素并调用add方法来处理 addAll
。
所以最终我做了什么,希望这能帮到其他人。
class NoDuplicatesList<E> extends LinkedList<E> {
@Override
public boolean add(E e) {
if (this.contains(e)) {
return false;
}
else {
return super.add(e);
}
}
@Override
public boolean addAll(Collection<? extends E> collection) {
Collection<E> copy = new LinkedList<E>(collection);
copy.removeAll(this);
return super.addAll(copy);
}
@Override
public boolean addAll(int index, Collection<? extends E> collection) {
Collection<E> copy = new LinkedList<E>(collection);
copy.removeAll(this);
return super.addAll(index, copy);
}
@Override
public void add(int index, E element) {
if (this.contains(element)) {
return;
}
else {
super.add(index, element);
}
}
}
Set<Integer>
来解决,该集合存储元素的哈希码(而不是搜索整个列表)-当然,这需要所有元素正确实现hashCode(),但是使用像Lombok这样的辅助框架,这真的不是问题...实际上有点琐碎。
甚至可以使用红黑树优化该解决方案的哈希码...对于大量性能提升的小内存开销;欢迎来到云计算的世界;-) - specializtnew ArrayList( new LinkedHashSet() )
new ArrayList(set)
中(或者new LinkedList(set)
,任选其一)。NoDuplicatesList
存在一些问题,主要是contains()
方法,此外你的类没有处理检查传递给addAll()
方法的集合中是否有重复项。我需要类似的功能,于是我去了commons collections并使用了SetUniqueList
,但当我运行一些性能测试时,我发现与使用Set.toArray()
方法获得一个Array
相比,它似乎没有被优化。
相比其他实现方式,SetUniqueTest
填充并遍历100,000个字符串所需的时间是20:1倍,这是一个很大的差别。
因此,如果您担心性能问题,我建议您使用Set和获取数组,而不是使用SetUniqueList
,除非您真的需要SetUniqueList
的逻辑,那么您将需要检查其他解决方案...
测试代码主方法:
public static void main(String[] args) {
SetUniqueList pq = SetUniqueList.decorate(new ArrayList());
Set s = new TreeSet();
long t1 = 0L;
long t2 = 0L;
String t;
t1 = System.nanoTime();
for (int i = 0; i < 200000; i++) {
pq.add("a" + Math.random());
}
while (!pq.isEmpty()) {
t = (String) pq.remove(0);
}
t1 = System.nanoTime() - t1;
t2 = System.nanoTime();
for (int i = 0; i < 200000; i++) {
s.add("a" + Math.random());
}
s.clear();
String[] d = (String[]) s.toArray(new String[0]);
s.clear();
for (int i = 0; i < d.length; i++) {
t = d[i];
}
t2 = System.nanoTime() - t2;
System.out.println((double)t1/1000/1000/1000); //seconds
System.out.println((double)t2/1000/1000/1000); //seconds
System.out.println(((double) t1) / t2); //comparing results
敬礼, Mohammed Sleem
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashSet;
/**
* Extends <tt>ArrayList</tt> and guarantees no duplicate elements
*/
public class UniqueArrayList<T> extends ArrayList<T> {
private static final long serialVersionUID = 1L;
public UniqueArrayList(int initialCapacity) {
super(initialCapacity);
}
public UniqueArrayList() {
super();
}
public UniqueArrayList(T[] array) {
this(Arrays.asList(array));
}
public UniqueArrayList(Collection<? extends T> col) {
addAll(col);
}
@Override
public void add(int index, T e) {
if (!contains(e)) super.add(index, e);
}
@Override
public boolean add(T e) {
return contains(e) ? false : super.add(e);
}
@Override
public boolean addAll(Collection<? extends T> col) {
Collection set=new LinkedHashSet(this);
set.addAll(col);
clear();
return super.addAll(set);
}
@Override
public boolean addAll(int index, Collection<? extends T> col) {
Collection set=new LinkedHashSet(subList(0, index));
set.addAll(col);
set.addAll(subList(index, size()));
clear();
return super.addAll(set);
}
@Override
public T set(int index, T e) {
return contains(e) ? null : super.set(index, e);
}
/** Ensures element.equals(o) */
@Override
public int indexOf(Object o) {
int index=0;
for(T element: this){
if (element.equals(o)) return index;
index++;
}return -1;
}
}
从我的记忆中,列表允许重复项。您可以快速实现一个UniqueArrayList
并覆盖所有的add
/insert
函数,在调用继承方法之前检查contains()
。对于个人使用,您只需实现您使用的add
方法,并覆盖其他方法以防止未来的程序员以不同的方式使用列表而抛出异常。
这个怎么样?在添加之前,通过包含一个已经存在的对象来检查列表
while (searchResult != null && searchResult.hasMore()) {
SearchResult nextElement = searchResult.nextElement();
Attributes attributes = nextElement.getAttributes();
String stringName = getAttributeStringValue(attributes, SearchAttribute.*attributeName*);
if(!List.contains(stringName)){
List.add(stringName);
}
}