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