简体   繁体   English

java:Comparator和Treeset删除重复项

[英]java: Comparator and Treeset to remove duplicates

i have a java class like this 我有一个像这样的java类

public class A {

    private String field1;
    private String field2;

    // getters, setters but no equals and hashcode
}

and a list of objects of this class, i want to remove from this list all the duplicates elements that has the same field1 or the same field2, so i have 2 Comparators 和这个类的对象列表,我想从这个列表中删除所有具有相同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());
    }
}

so to do the task i use treeset like 所以要做我使用treeset的任务

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)

but how can i do the same using just one comparator and one treeset ? 但是我怎么能只使用一个比较器和一个树集来做同样的事情呢?

Thanks for the help 谢谢您的帮助

Update: 更新:

Thanks all for the answers, but after reading them i don't know if this is the right approach to the real problem. 谢谢所有的答案,但阅读后我不知道这是否是解决实际问题的正确方法。

In my real case field1 is like a phone number and field2 is like a name. 在我的实际案例中,field1就像一个电话号码,而field2就像一个名字。 So i don't want to call the same phone number more than one time (this is the first treeset to removes duplicates) and i don't want to call more than one time the same name (the second treeset to removes duplicates) 所以我不想多次调用相同的电话号码(这是第一个删除重复的树集),我不想多次调用相同的名称(第二个树集来删除重复项)

You can modify the class but i'd like to know if this approach is ok to resolve the real problem. 你可以修改类,但我想知道这种方法是否可以解决真正的问题。

If this approach is correct, from your question, i see that without modifying the class is not possible to use just one comparator 如果这种方法是正确的,从你的问题,我看到,如果不修改类,就不可能只使用一个比较器

Thanks 谢谢

You can't use one comparator to sort by two criteria at the same time, so there is no real way to go better than two TreeSets in your case. 您不能同时使用一个比较器按两个条件进行排序,因此在您的情况下,没有比两个TreeSet更好的方法。 Of course, you can wrap them in one data structure. 当然,您可以将它们包装在一个数据结构中。

(Alternatively you could use two HashMaps, each having one of the strings as key - this will be faster on average, but is more complicated to program.) (或者你可以使用两个HashMaps,每个都有一个字符串作为键 - 平均速度会更快,但编程起来会更复杂。)

You can't, and it's not clear to me that what you're trying to do is well-defined. 你不能,而且我不清楚你要做的事情是明确定义的。

Are you aware that your current approach depends both on the order in which elements are added and on whether you check field1 or field2 first for duplicates? 您是否知道您当前的方法取决于添加元素的顺序以及是否首先检查field1或field2是否为重复项? Imagine you had these objects of class A: 想象一下,你有A类的这些对象:

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

Checking field1 first gives the result [ab] or [ab, cd] , depending on the order added. 检查field1首先给出结果[ab][ab, cd] ,具体取决于添加的顺序。

Checking field2 first gives the result [cb] or [ab, cd] , depending on the order added. 检查field2首先给出结果[cb][ab, cd] ,具体取决于添加的顺序。

This is pretty strange behavior. 这是非常奇怪的行为。 Is this what you intended? 这是你的意图吗? I don't think it is possible to reproduce this with a single TreeSet and Comparator in the general case. 我不认为在一般情况下使用单个TreeSet和Comparator重现这一点。

If your intention is to do two levels of sorting(first: PhoneNumber and second:Name), then you can use the following code, where the duplicate check will be done against both the fields(field1 and field2). 如果您打算进行两个级别的排序(第一个:PhoneNumber和第二个:Name),那么您可以使用以下代码,其中将对两个字段(field1和field2)执行重复检查。 As we are already using compareTo for both the fields, it is not required to use equals and hashcode . 由于我们已经在两个字段中使用了compareTo ,因此不需要使用equalshashcode But it is always good practice to use hashcode and equals . 但是使用hashcodeequals总是好的做法。

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

} }

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

Generic function that adds items to hashset to make them unique, and then drop them to TreeSet to sort. 将项添加到hashset以使其唯一的通用函数,然后将它们放到TreeSet中进行排序。 You can use it with: TreeSet<A> ts1 = getTreeSet(list); 你可以使用它: TreeSet<A> ts1 = getTreeSet(list); .

This approach works well for a fixed list. 这种方法适用于固定列表。

@BalusC No, this assumes @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
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM