【问题标题】:What kind of List<?> will automatically eliminate duplicates [duplicate]什么样的 List<?> 会自动消除重复[重复]
【发布时间】:2010-09-24 07:24:54
【问题描述】:

什么样的List在添加时会自动消除重复项。

例如对于列表,如果我添加 1,2,3,4,5,1,2,3 = 列表应该只包含 1,2,3,4,5

【问题讨论】:

    标签: java


    【解决方案1】:

    如果要消除重复,请使用Set

    【讨论】:

      【解决方案2】:

      Set 会自动消除重复,但它是 Collection 而不是 List。

      我认为标准库中没有消除重复项的 List。

      Java 6 SE API 文档的Annotated Outline of the Collections Framework 页面显示“通常允许重复”。

      【讨论】:

      • +1 用于指出 Sets 和 Lits 之间的区别。
      【解决方案3】:

      【讨论】:

      • LinkedHashSet 是 Set 接口的一种实现......为什么你推荐这个而不是另一个?
      • @pgras,也许是因为添加元素的顺序保持不变,就像一个列表一样。
      • @Wolfgang, @Bart K - 问题是 LinkedHashSet 不是列表。它实现了 Set API,并且不允许您按位置获取、更新或插入或删除元素。
      • 您可以使用 for(element e : collection) 按添加的顺序遍历它,即使直接位置访问不可用,这也很重要
      • @Wolfgang - 1) 正如我之前的评论所解释的,LinkedHashSet 没有表现出真实列表的特征。 2)一个更好的主意是实现一个真正的集合/列表混合。 ArrayList 和 HashSet 的包装器可以完成这项工作。
      【解决方案4】:

      不要像有人建议的那样,实现自己的 List 来进行重复检查,如果在 add() 处存在重复则返回 false。

      为什么?因为你会破坏 List 接口契约,上面写着:

      public boolean add(E e)
      [...]
      Returns:
               true (as specified by Collections.add())
      

      List.add(E e) 必须返回 true 并将元素添加到列表中,或者抛出异常。列表并不意味着有重复检查,这就是集合的用途。

      【讨论】:

        【解决方案5】:

        正如上面的海报所说,没有具有唯一处理的列表。

        List (Java Platform SE 6)

        与集合不同,列表通常允许重复元素。更正式地说,列表通常允许元素 e1 和 e2 对,例如 e1.equals(e2),并且如果它们完全允许 ​​null 元素,它们通常允许多个 null 元素。有人可能希望通过在用户尝试插入它们时抛出运行时异常来实现一个禁止重复的列表,这并非不可想象,但我们希望这种用法很少见。

        【讨论】:

        • 稀有......而且价格昂贵。抛出异常是昂贵的。
        • 昂贵,真的。但有时是不可避免的。许多收集方法抛出 UnsupportedOperationException 并且客户端代码无法提前发现它们。 RuntimeExceptions 是你必须在集合框架中处理的事情。
        【解决方案6】:

        您可以扩展现有的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。

        【讨论】:

        • 我喜欢这个,而且我会这样做。这特别维护了 List 的所有语义,同时强制执行无重复约束(尽管以一些内存为代价)。 p.s.删除元素时不要忘记同步您的支持 HashSet...
        • 我正在考虑做一些非常相似的事情,但我很想你会实现 add(index, E) 实现。我想如果您在数据中找到 E 的副本,那么您无法在该位置插入。 add(index, E) 的 List 接口返回 void,因此您无法报告此失败情况。
        【解决方案7】:

        你可能想要一个 Set,例如HashSet(),而不是 List?没有列表会消除重复,根据定义列表允许它们。

        【讨论】:

          【解决方案8】:

          当时你可以创建自己的类,@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);
          
              }
          }
          

          【讨论】:

            【解决方案9】:

            这是拒绝重复的 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){}
            };
            

            【讨论】:

              【解决方案10】:

              获得已排序且没有重复的实际List 的最简单方法是像这样包装它:

              List<Integer> unique = 
                new ArrayList<Integer>(new TreeSet<Integer>(Arrays.asList(1, 1, 2, 2, 3, 3)));
              

              请注意,当您添加到此列表时,重复项将不会被消除,但也许这对您有用。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2013-02-06
                • 1970-01-01
                • 1970-01-01
                • 2016-07-02
                • 2011-01-16
                • 1970-01-01
                相关资源
                最近更新 更多