【问题标题】:remove duplicate strings in a List in Java删除Java列表中的重复字符串
【发布时间】:2012-12-26 12:04:44
【问题描述】:

更新: 我猜HashSet.add(Object obj) 不会打电话给contains。有没有办法实现我想要的(删除 dup 字符串忽略大小写使用Set)?

原问题: 试图从java中的String列表中删除dups,但是在下面的代码中CaseInsensitiveSet.contains(Object ob)没有被调用,为什么?

public static List<String> removeDupList(List<String>list, boolean ignoreCase){
    Set<String> set = (ignoreCase?new CaseInsensitiveSet():new LinkedHashSet<String>());
    set.addAll(list);

    List<String> res = new Vector<String>(set);
    return res;
}


public class CaseInsensitiveSet  extends LinkedHashSet<String>{

    @Override
    public boolean contains(Object obj){
        //this not getting called.
        if(obj instanceof String){

            return super.contains(((String)obj).toLowerCase());
        }
        return super.contains(obj);
    }

}

【问题讨论】:

  • 请学习如何使用代码格式化而不是使用&lt;pre&gt; 语句。
  • 你为什么要清除我的编辑?
  • 是否要保留列表中字符串的顺序?如果是这样,对于重复项,您要占据第一次出现的位置还是最后一次出现的位置?

标签: java collections set


【解决方案1】:

contains 没有被调用,因为 LinkedHashSet 没有以这种方式实现。

如果你想让 add() 调用 contains() 你也需要覆盖它。

没有以这种方式实现的原因是,首先调用 contains 意味着您正在执行两个查找,而不是一个更慢的查找。

【讨论】:

    【解决方案2】:

    LinkedHashSetadd() 方法不要在内部调用contains(),否则你的方法也会被调用。

    而不是LinkedHashSet,为什么不使用SortedSet 和不区分大小写的比较器 ?使用String.CASE_INSENSITIVE_ORDER 比较器

    你的代码被简化为

    public static List<String> removeDupList(List<String>list, boolean ignoreCase){
        Set<String> set = (ignoreCase?new TreeSet<String>(String.CASE_INSENSITIVE_ORDER):new LinkedHashSet<String>());
        set.addAll(list);
    
        List<String> res = new ArrayList<String>(set);
        return res;
    }
    

    如果您希望保留订单,正如@tom anderson 在他的评论中指定的那样,您可以为订单使用辅助 LinkedHashSet。

    您可以尝试将该元素添加到 TreeSet,如果返回 true 也将其添加到 LinkedHashSet,否则不添加。

    public static List<String> removeDupList(List<String>list){
            Set<String> sortedSet = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
            List<String> orderedList = new ArrayList<String>();
            for(String str : list){
                 if(sortedSet.add(str)){ // add returns true, if it is not present already else false
                     orderedList.add(str);
                 }
            }
            return orderedList;
        }
    

    【讨论】:

    • 正如我对 Evgeniy 的回答所评论的那样,这不会保留列表中字符串的顺序,这可能会或可能不会重要。
    • 感谢您指出。我已经更新了代码以保留元素的顺序。
    • 与其建立orderedSet,然后将其转换为ArrayList,不如直接建立ArrayListorderedSet 是一个集合这一事实在这里实际上并不需要。
    【解决方案3】:

    试试

            Set set = new TreeSet(String.CASE_INSENSITIVE_ORDER);
            set.addAll(list);
            return new ArrayList(set);
    

    更新,但正如汤姆安德森所说,它不会保留初始顺序,如果这确实是一个问题,请尝试

        Set<String> set = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
        Iterator<String> i = list.iterator();
        while (i.hasNext()) {
            String s = i.next();
            if (set.contains(s)) {
                i.remove();
            }
            else {
                set.add(s);
            }
        }
    

    打印

    [2, 1]
    

    【讨论】:

    • 如果提问者不关心保留列表中的顺序,那么这是一个很好的答案。如果他这样做了,可悲的是,这只是一个好人。
    【解决方案4】:

    试试

        public boolean addAll(Collection<? extends String> c) {
                for(String s : c) {
                if(! this.contains(s)) {
                    this.add(s);
                }
            }
            return super.addAll(c);
        }
        @Override
        public boolean contains(Object o) {
            //Do your checking here
    //      return super.contains(o);
        }
    

    如果您希望代码通过那里,这将确保调用 contains 方法。

    【讨论】:

      【解决方案5】:

      这是另一种方法,使用字符串的HashSet 进行重复数据删除,但直接构建结果列表:

      public static List<String> removeDupList(List<String> list, boolean ignoreCase) {
          HashSet<String> seen = new HashSet<String>();
          ArrayList<String> deduplicatedList = new ArrayList<String>();
          for (String string : list) {
              if (seen.add(ignoreCase ? string.toLowerCase() : string)) {
                  deduplicatedList.add(string);
              }
          }
          return deduplicatedList;
      }
      

      这相当简单,只对元素进行一次传递,并且只对小写字母进行哈希查找,然后为每个元素添加一个列表。

      【讨论】:

        猜你喜欢
        • 2014-09-16
        • 2014-08-02
        • 1970-01-01
        • 1970-01-01
        • 2011-12-17
        • 1970-01-01
        • 2016-10-24
        • 2019-05-05
        • 1970-01-01
        相关资源
        最近更新 更多