Удалить дубликат элемента из набора в java

У меня есть набор строковых массивов, и я хочу удалить из него повторяющиеся элементы...

    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"}]

Я знаю несколько способов...

  • Каждый раз, когда мне нужно запустить внутренний цикл и проверить его дубликат или нет.
  • Могу ли я переопределить поведение набора? (hashcode или равно)? (я не знаю, как....)
  • Нужно ли мне изменять структуру данных для этого? (связанныйhashset или список или любая другая подходящая структура данных для этого?)

Ответ 1

Массивы наследуются от Object и не переопределяют методы hashCode и equals. A HashSet использует реализацию Map, которая, в свою очередь, использует hashCode и equals, чтобы избежать дублирования элементов.

Вы можете использовать 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;
}

Ответ 2

Хэш-код array не зависит от содержимого array (он наследует хэш-код Object, который использует ссылку массива).

Однако List будет делать то, что вы хотите. Он использует хэш-код на основе элементов в List. Из 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

Ответ 3

Массивы используют реализацию identity-based Object.hashCode(), и нет простого способа проверить, равны ли они. Если вы все еще хотите продолжить свою задачу, я предлагаю вам использовать TreeSet с помощью Comparator

Хотя и не поддающийся проверке подход, но вы должны иметь возможность построить точное настроенное решение из моего примера,

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;
    }

Ответ 4

Почему бы не использовать реализацию 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 поддерживается хэшмапом, который использует функцию hashcode как свой ключ. Поэтому на самом деле вам нужно переопределить hashcode для представления ваших критериев равных.

Одна проблема с этим. Я считаю, что String и, следовательно, String [] объявлены как final, поэтому вы не можете их расширять: (

Ответ 5

вместо того, чтобы брать массив строки, вы можете создать класс Как это..

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;

}


}

И после этого insteed строки вы можете взять этот один объект класса. замените HashSet на TreeSet. Вот так.

     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());

Итак, это будет сортироваться, и это также проверяет наличие дубликата.

Ответ 6

попробуйте этот код.............

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);
    }
}
}

Ответ 7

Попробуйте что-нибудь подобное...

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

True

Ответ 8

Здесь вместо сохранения Set вы можете использовать Set < SomeClass > и переопределить метод hash и equals для класса SomeClass, чтобы он решил вашу проблему.