【发布时间】:2010-09-24 07:24:54
【问题描述】:
什么样的List在添加时会自动消除重复项。
例如对于列表,如果我添加 1,2,3,4,5,1,2,3 = 列表应该只包含 1,2,3,4,5
【问题讨论】:
标签: java
什么样的List在添加时会自动消除重复项。
例如对于列表,如果我添加 1,2,3,4,5,1,2,3 = 列表应该只包含 1,2,3,4,5
【问题讨论】:
标签: java
如果要消除重复,请使用Set
【讨论】:
Set 会自动消除重复,但它是 Collection 而不是 List。
我认为标准库中没有消除重复项的 List。
Java 6 SE API 文档的Annotated Outline of the Collections Framework 页面显示“通常允许重复”。
【讨论】:
【讨论】:
不要像有人建议的那样,实现自己的 List 来进行重复检查,如果在 add() 处存在重复则返回 false。
为什么?因为你会破坏 List 接口契约,上面写着:
public boolean add(E e)
[...]
Returns:
true (as specified by Collections.add())
List.add(E e) 必须返回 true 并将元素添加到列表中,或者抛出异常。列表并不意味着有重复检查,这就是集合的用途。
【讨论】:
正如上面的海报所说,没有具有唯一处理的列表。
与集合不同,列表通常允许重复元素。更正式地说,列表通常允许元素 e1 和 e2 对,例如 e1.equals(e2),并且如果它们完全允许 null 元素,它们通常允许多个 null 元素。有人可能希望通过在用户尝试插入它们时抛出运行时异常来实现一个禁止重复的列表,这并非不可想象,但我们希望这种用法很少见。
【讨论】:
您可以扩展现有的java.util.ArrayList 并将java.util.Set 封装在其中。您应该覆盖所有add(...)、addAll(...) 和remove 方法,并首先检查一个元素是否在封装集中(在将其添加到列表的情况下):
public class ListSet<E> extends ArrayList<E> {
private Set<E> set;
public ListSet() {
set = new HashSet<E>();
}
@Override
public boolean add(E element) {
if(set.add(element)) {
super.add(element);
return true;
}
return false;
}
// other add and remove methods
}
编辑
正如@Alnitak 提到的:不要忘记在删除元素时同步您的支持 HashSet。
【讨论】:
你可能想要一个 Set,例如HashSet(),而不是 List?没有列表会消除重复,根据定义列表允许它们。
【讨论】:
当时你可以创建自己的类,@Override 为你的类添加方法。
“看看我的代码并练习吧”
import java.util.ArrayList;
import java.util.List;
class MyList extends ArrayList<Integer> {
private static final long serialVersionUID = 1L;
@Override
public boolean add(Integer element) {
if (!found(element)) {
super.add(element);
}
return false;
}
public boolean found(Integer e) {
return equals(e);
}
public boolean equals(Integer e) {
for (int i = 0; i < super.size(); i++) {
if (super.get(i).equals(e))
return true;
}
return false;
}
}
public class ListRemovingDuplicated {
public static void main(String[] abd) {
List<Integer> obj = new MyList();
obj.add(10);
obj.add(20);
obj.add(10);
obj.add(10);
obj.add(30);
System.out.println(obj);
}
}
【讨论】:
这是拒绝重复的 ArrayList 的扩展:
public class NoDupeList<E> extends ArrayList<E>{
private static final long serialVersionUID = -2682691450003022201L;
public NoDupeList(){
super();
}
public NoDupeList(final Collection<? extends E> c){
super(c instanceof Set<?> ? c : new LinkedHashSet<E>(c));
}
public NoDupeList(final int initialCapacity){
super(initialCapacity);
}
@Override
public boolean add(final E e){
return !this.contains(e) && super.add(e);
};
@Override
public boolean addAll(final Collection<? extends E> c){
final List<E> intermediate = new ArrayList<E>(c);
intermediate.removeAll(this);
return super.addAll(intermediate);
}
@Override
public void add(final int index, final E element){
if(!this.contains(element)){
super.add(index, element);
}
};
@Override
public E set(final int index, final E element){
if(this.contains(element) && !this.get(index).equals(element)){
throw new IllegalArgumentException("This would cause a duplicate");
}
return super.set(index, element);
};
}
我唯一不能处理的是set() 方法。我的解决方案是抛出一个IllegalArgumentException,如果这会导致重复,但也许人们通常应该让这个方法抛出一个UnsupportedOperationException。
不管怎样,这里有一个测试方法:
@Test
public void testNoDupeList() throws Exception{
final List<String> list =
new NoDupeList<String>(Arrays.asList("abc", "def", "abc"));
assertEquals(list, Arrays.asList("abc", "def"));
list.addAll(Arrays.asList("abc", "def", "ghi"));
assertEquals(list, Arrays.asList("abc", "def", "ghi"));
try{
list.set(2, "abc");
fail("This should have caused an Exception");
} catch(final Exception e){}
};
【讨论】:
获得已排序且没有重复的实际List 的最简单方法是像这样包装它:
List<Integer> unique =
new ArrayList<Integer>(new TreeSet<Integer>(Arrays.asList(1, 1, 2, 2, 3, 3)));
请注意,当您添加到此列表时,重复项将不会被消除,但也许这对您有用。
【讨论】: