java:比较器和树集删除重复项

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5601967/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 11:51:35  来源:igfitidea点击:

java: Comparator and Treeset to remove duplicates

javaduplicatescomparatortreeset

提问by res1

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<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. 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)

在我的真实案例中,field1 就像一个电话号码,而 field2 就像一个名字。所以我不想多次拨打同一个电话号码(这是第一个删除重复项的树集),我不想多次拨打同一个电话号码(第二个删除重复项的树集)

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

谢谢

采纳答案by rlibby

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? Imagine you had these objects of class A:

您是否知道您当前的方法取决于添加元素的顺序以及您是否首先检查 field1 或 field2 是否有重复项?想象一下,你有这些 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 重现这一点。

回答by Pa?lo Ebermann

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. Of course, you can wrap them in one data structure.

您不能使用一个比较器同时按两个条件进行排序,因此在您的情况下,没有比两个 TreeSet 更好的方法。当然,您可以将它们包装在一种数据结构中。

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

(或者,您可以使用两个 HashMap,每个都有一个字符串作为键 - 这平均会更快,但编程更复杂。)

回答by Jagadeesh

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). As we are already using compareTofor both the fields, it is not required to use equalsand hashcode. But it is always good practice to use hashcodeand equals.

如果您打算进行两级排序(第一个:PhoneNumber 和第二个:Name),那么您可以使用以下代码,其中将对两个字段(field1 和 field2)进行重复检查。由于我们已经对这两个字段使用了compareTo,因此不需要使用equalshashcode。但是使用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;
}

}

}

回答by shyam sanju

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

回答by Margus

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. You can use it with: TreeSet<A> ts1 = getTreeSet(list);.

将项目添加到 hashset 以使其唯一的通用函数,然后将它们放到 TreeSet 进行排序。您可以将它与: 一起使用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
}