3

更新:我猜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);
    }

}
4

5 回答 5

7

尝试

        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]
于 2012-12-26T12:09:53.020 回答
5

contains不被称为 LinkedHashSet 不是以这种方式实现的。

如果您希望 add() 调用 contains() 您还需要覆盖它。

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

于 2012-12-26T12:08:23.860 回答
3

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

LinkedHashSet为什么不使用SortedSet不区分大小写的比较器而不是 a ?使用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;
    }
于 2012-12-26T12:18:20.690 回答
0

尝试

    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 方法。

于 2012-12-26T12:34:30.540 回答
0

这是另一种方法,使用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;
}

这相当简单,只对元素进行一次传递,并且只对每个元素进行小写、哈希查找和列表追加。

于 2012-12-26T13:31:22.367 回答