从java中的集合中删除重复元素

时间:2013-12-17 05:06:36

标签: java set

我有一组字符串数组,我想删除此中的重复元素...

    String[] arr1 = {"a1","b1"};
    String[] arr2 = {"a2","b2"};
    Set<String[]> mySet = new HashSet<String[]>();
    mySet.add(arr1);
    mySet.add(arr2);
    mySet.add(new String[] {"a1","b1"});
    System.out.print(mySet.size());

目前mySet看起来像这样:

[{"a1","b1"},{"a2","b2"},{"a1","b1"}]

但我想这样:

[{"a1","b1"},{"a2","b2"}]

我知道某些方法......

  1. 每次我需要运行内部循环并检查它是否重复。
  2. 我可以覆盖该集的行为吗? (哈希码或等号)? (我不知道怎么......)
  3. 我需要更改数据结构吗? (linkedhashset或list或任何其他合适的数据结构?)

8 个答案:

答案 0 :(得分:11)

数组继承自Object,不会覆盖hashCodeequals方法。 HashSet使用Map实施,后者又使用hashCodeequals来避免重复元素。

您可以将TreeSet与自定义Comparator一起使用,以便将String数组进行比较以获得相等。

Set<String[]> mySet = new TreeSet<>(new Comparator<String[]>() {

  @Override
  public int compare(String[] o1, String[] o2) {
    return Arrays.equals(o1, o2)? 0 : Arrays.hashCode(o1) - Arrays.hashCode(o2);
  }

});

请注意,这只会忽略具有相同对应元素的重复数组。如果元素的顺序不同,则不会将其视为重复。

如果您希望能够丢弃无序重复项,例如{a1, b1}{b1, a1},请使用此项:

@Override
public int compare(String[] o1, String[] o2) {
    int comparedHash = o1.hashCode() - o2.hashCode();
    if(o1.length != o2.length) return comparedHash;
    List<String> list = Arrays.asList(o1);
    for(String s : o2) {
        if(!list.contains(s)) return comparedHash;
    }
    return 0;
}

答案 1 :(得分:10)

array哈希码独立于array的内容(它继承了使用数组引用的Object哈希码。)

然而,List会做你想要的。它使用基于List中元素的哈希码。 From Java Docs

int hashCode = 1;
for (E e : list)
    hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());

示例:

List<String> list1 = Arrays.asList("a1","b1");
List<String> list2 = Arrays.asList("a2","b2");
Set<List<String>> mySet = new HashSet<List<String>>();
mySet.add(list1);
mySet.add(list2);
mySet.add(Arrays.asList("a1","b1"));   // duplicate won't be added
System.out.print(mySet.size());        // size = 2

答案 2 :(得分:3)

Arrays使用identity-based Object.hashCode()实现,没有简单的方法来检查它们是否相等。如果您还想继续解决问题,我建议您使用TreeSet与比较器

虽然不是故障证明方法,但你应该能够从我的例子中构建精细调整的解决方案,

public static void main(String[] args) {
          String[] arr1 = {"a1","b1"};
            String[] arr2 = {"a2","b2"};
            Set<String[]> mySet = new TreeSet<String[]>(new ArrayComparator());
            mySet.add(arr1);
            mySet.add(arr2);
            mySet.add(new String[] {"a1","b1"});
            System.out.println(mySet.size());
            for(String[] aa: mySet){
                System.out.println(aa[0]+" , "+aa[1]);
            }
    }
}

 class ArrayComparator implements Comparator {

    @Override
    public int compare(Object o1, Object o2) {
        String[] ar1 =(String[]) o1;
        String[] ar2 =(String[]) o2;
        if(ar1.length!=ar2.length){
            return -1;
        }
        for(int count=0;count<ar1.length;count++){
            if(!ar1[count].equals(ar2[count])){
                return -1;
            }
        }
        return 0;
    }

答案 3 :(得分:2)

为什么不使用List实现? list.equals将比较每个列表中的元素并确定相等性。

List<String> arr1 = new ArrayList<String>();
arr1.add("a1");
arr1.add("b1");
List<String> arr2 = new ArrayList<String>();
arr2.add("a2");
arr2.add("b2");
Set<List<String>> mySet = new HashSet<List<String>>();
mySet.add(arr1);
mySet.add(arr2);

List<String> arr3 = new ArrayList<String>();
arr3.add("a1");
arr3.add("b1");
mySet.add(arr3);
System.out.print(mySet.size());

您建议覆盖equals和hashcode方法。 HashSet由使用哈希码函数作为其键的哈希映射支持。实际上,您需要覆盖哈希码来表示您的等于标准。

这个问题。我相信String和String []被声明为final,所以你不能扩展它们:(

答案 4 :(得分:2)

而不是采用字符串数组,你可以创建一个像这样的类..

public class String1 implements Comparable<String1>{

String str1;
String str2;

public String1(String a, String b) {
    str1 = a;
    str2 = b;
}

public String getStr1() {
    return str1;
}
}

public String getStr2() {
    return str2;
}

@Override
public String toString() {
    return "String1 [str1=" + str1 + ", str2=" + str2
            + "]";
}

@Override
public int compareTo(String1 o) {
    if(str1.contentEquals(o.getStr1()) && str2.contentEquals(o.getStr2()))  return 0 ; 
    return 1;

}


}

在输入字符串之后,您可以使用这个类对象。 用TreeSet替换HashSet。像这样。

     String1 arr1 =new String1("a1","b1");
     String1 arr2 =new String1("a2","b2");
     Set<String1> mySet = new TreeSet<String1>();
     mySet.add(arr1);
     mySet.add(arr2);
     mySet.add(new String1("a1","b1"));
     System.out.print(mySet.size());
     System.out.println(mySet.toString());

所以这也将排序,这也将检查重复。

答案 5 :(得分:2)

尝试此代码.............

import java.util.HashSet;
import java.util.Set;

public class setDemo {
static Set<String[]> mySet = new HashSet<String[]>();
static Set tempSet = new HashSet();
public static void main(String[] args) {

      String[] arr1 = {"a1","b1"};
      String[] arr2 = {"a2","b2"};

        addObject(arr1);
        addObject(arr2);
        addObject(new String[] {"a1","b1"});
        System.out.print(mySet.size());
       // System.out.println(tempSet);
}
public static void addObject(String[] o){
    StringBuffer sb = new StringBuffer();
    for(Object obj:o){
        sb.append(obj.toString());
    }
    if(!tempSet.contains(sb.toString())){
        tempSet.add(sb.toString());
        mySet.add(o);
    }
}
}

答案 6 :(得分:1)

尝试这样的事情......

public static void main(String... args) {
        String[] arr1 = {"a1","b1"};
        String[] arr2 = {"a2","b2"};
        Set<String[]> mySet = new HashSet<String[]>();
        mySet.add(arr1);
        mySet.add(arr2);
        String str[] =new String[] {"a1","b1"}; 
        long t1 = System.nanoTime();
        boolean b =checkContains(str,mySet);
        long t2=System.nanoTime();
        long t = t2-t1;
        System.out.println("time taken : " + t );
        System.out.println(b);

        if(!b)
        {
            mySet.add(str);

        }


    }

    public static boolean checkContains(String[] str, Set mySet)
    {  
        Iterator it = mySet.iterator();
        while(it.hasNext())
        {
            String[] arr = (String[])it.next();
            if(arr[0].equals(str[0]) && arr[1].equals(str[1]) )
            {
                return true;
            }
        }


         return false;
    }

OP:

  

所用时间:184306

     

答案 7 :(得分:1)

此处不使用Set,您可以使用Set&lt; SomeClass &gt;并覆盖SomeClass类的hash和equals方法,因此它将解决您的问题。