Java: компаратор и Treeset для удаления дубликатов - PullRequest
3 голосов
/ 09 апреля 2011

у меня есть такой класс java

public class A {

    private String field1;
    private String field2;

    // getters, setters but no equals and hashcode
}

и список объектов этого класса, я хочу удалить из этого списка все дубликаты элементов, которые имеют одинаковое field1 или одинаковое field2, поэтомуу меня есть 2 компаратора

public class Comparator1 implements Comparator<A> {
    public int compare(A o1, A o2) {

        return o1.getField1().compareToIgnoreCase( o2.getField1() );
    }
}

public class Comparator2 implements Comparator<A> {
    public int compare(A o1, A o2) {

        return o1.getField2().compareToIgnoreCase(o2.getField2());
    }
}

, поэтому для выполнения задачи я использую набор деревьев, например

TreeSet<A> ts1 = new TreeSet<A>(new Comparator1())
ts1.addAll(list)

TreeSet<A> ts2 = new TreeSet<A>(new Comparator2())
ts2.addAll(ts1)

list.clear()
list.addAll(ts2)

, но как мне сделать то же самое, используя только один компаратор и один набор деревьев?

Спасибо за помощь

Обновление:

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

В моем реальном случае поле 1 похоже на номер телефона, а поле 2 - на имя.Поэтому я не хочу вызывать один и тот же номер телефона более одного раза (это первый набор деревьев, который удаляет дубликаты), и я не хочу вызывать более одного раза одно и то же имя (второй набор деревьев, который удаляет дубликаты)

Вы можете изменить класс, но я хотел бы знать, подходит ли этот подход для решения реальной проблемы.

Если этот подход верен, из вашего вопроса я вижу, что без измененияКласс не возможно использовать только один компаратор

Спасибо

Ответы [ 5 ]

2 голосов
/ 09 апреля 2011

Вы не можете использовать один компаратор для сортировки по двум критериям одновременно, поэтому в вашем случае нет лучшего способа пойти лучше, чем два TreeSets. Конечно, вы можете обернуть их в одну структуру данных.

(В качестве альтернативы вы можете использовать две HashMaps, каждая из которых имеет одну из строк в качестве ключа - в среднем это будет быстрее, но сложнее для программирования.)

1 голос
/ 09 апреля 2011

Вы не можете, и мне не ясно, что то, что вы пытаетесь сделать, четко определено.

Знаете ли вы, что ваш текущий подход зависит как от порядка добавления элементов?и проверяете ли вы сначала field1 или field2 на наличие дубликатов?Представьте, что у вас есть эти объекты класса A:

A ab = new A("a", "b");
A cb = new A("c", "b");
A cd = new A("c", "d");

Проверка поля1 сначала дает результат [ab] или [ab, cd], в зависимости от добавленного порядка.

Проверка поля2 сначала дает результат[cb] или [ab, cd], в зависимости от добавленного порядка.

Это довольно странное поведение.Это то, что вы хотели?Я не думаю, что это возможно воспроизвести с помощью одного TreeSet и Comparator в общем случае.

0 голосов
/ 16 марта 2018
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Set;
 import java.util.TreeSet;
 import java.util.Comparator;
 import java.util.List;

 public class RemoveDuplicate {

public static void main(String[] args) {
    Set<Student> set = new TreeSet<Student>();
    List<Student> students = Arrays.asList(new Student("Student1", "1005"), new Student("Student2", "1004"),
            new Student("Student3", "1003"), new Student("Student6", "1002"), new Student("Student5", "1001"),
            new Student("Student6", "1000"));

    // Sorting Using Lambda

    students.sort(new Comparator<Student>() {

        @Override
        public int compare(Student s1, Student s2) {

            return s1.getId().compareTo(s2.getId());
        }

    });

    System.out.println(students);
    set.addAll(students);

    System.out.println("\n***** After removing duplicates *******\n");

    final ArrayList<Student> newList = new ArrayList<Student>(set);

    /** Printing original list **/
    System.out.println(newList);
}

  }

 class Student implements Comparable<Student> {
private String name;
private String id;

public Student(String name, String id) {
    this.name = name;
    this.id = id;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public String getId() {
    return id;
}

public void setId(String id) {
    this.id = id;
}

@Override
public String toString() {
    return "\n" + "Name=" + name + "   Id=" + id;
}

@Override
public int compareTo(Student o1) {
    if (o1.getName().equalsIgnoreCase(this.name)) {
        return 0;
    }
    return 1;
    }

// public static Comparator<Student> StudentIdComparator = (Student
// s1,Student s2) -> s1.getId().compareTo(s2.getId());
   }
0 голосов
/ 27 мая 2014

Если вы намереваетесь выполнить два уровня сортировки (первый: PhoneNumber и второй: Имя), то вы можете использовать следующий код, где будет проверяться дубликат обоих полей (field1 и field2). Поскольку мы уже используем compareTo для обоих полей, не обязательно использовать равно и хэш-код . Но всегда полезно использовать хеш-код и равно .

public class A implements Comparable<A> {

private String field1;
private String field2;

public A(String number, String name) {
    this.field1 = number;
    this.field2 = name;
}

// First level sorting will be done by field1. 
// If field1 is equal then second level sorting will be done on field2
@Override
public int compareTo(A o) {
    int compareTo = field1.compareTo(o.getNumber());
    if(compareTo==0){
        return field2.compareTo(o.getName());
    }
    return compareTo;
}

public String getNumber() {
    return field1;
}

public String getName() {
    return field2;
}

}

0 голосов
/ 09 апреля 2011
public static <A extends Comparable<?>>  TreeSet<A> getTreeSet(Collection<A> list){
    TreeSet<A> result = new TreeSet<A>();
    HashSet<A> unique = new HashSet<A>();
    unique.addAll(list);
    result.addAll(unique);
    return result;
}

Общая функция, которая добавляет элементы в хэш-набор, чтобы сделать их уникальными, а затем помещает их в TreeSet для сортировки. Вы можете использовать его с: TreeSet<A> ts1 = getTreeSet(list);.

Этот подход хорошо работает для фиксированного списка.

@ BalusC Нет, это предполагает

public class A implements Comparable<A> {

    private String field1;
    private String field2;

    @Override
    public int compareTo(A o) {
        // No null checks, because it's illegal anyways.
        int tmp = 0;
        if ((tmp = field1.compareToIgnoreCase(o.field1)) != 0)
            return tmp;
        if ((tmp = field2.compareToIgnoreCase(o.field2)) != 0)
            return tmp;
        return tmp;
    }
    // getters, setters but no equals and hashcode
}
...