根据多个条件删除列表中的重复项

时间:2018-03-28 21:27:21

标签: java list collections

我有一个列表,其中包含我要清理的重复Student个对象。如果列表中的对象具有相同的名称和ID,则应将其删除。

有人可以帮助下面的Comparator实现吗?

public class RemoveDuplicate {
public static void main(String[] args) {
    final ArrayList students = new ArrayList();
    students.add(new Student("Student1", "1000", "1"));
    students.add(new Student("Student2", "1001", "2"));
    students.add(new Student("Student3", "1002", "3"));
    students.add(new Student("Student4", "1001", "4"));
    students.add(new Student("Student1", "1003", "45"));
    students.add(new Student("Student1", "1000", "46"));
    students.add(new Student("Student4", "1001", "47"));
    Set set = new TreeSet(new StudentsComparator());
    set.addAll(students);
    final ArrayList newList = new ArrayList(set);
    System.out.println(newList);
}
}
class StudentsComparator implements Comparator<Student> {
@Override
public int compare(Student s1, Student s2) {
    System.out.println(s1 + "," + s2);
    if (s1.getId().equalsIgnoreCase(s2.getId())) {
        if (s1.getNum().equalsIgnoreCase(s2.getNum())) {
            System.out.println("return0");
            return 0;
        }
    }
    return 1;
}
}

实际输出:

Name=Student1   Id=1000   Num=1, 
Name=Student2   Id=1001   Num=2, 
Name=Student3   Id=1002   Num=3, 
Name=Student4   Id=1001   Num=4, 
Name=Student1   Id=1003   Num=45, 
Name=Student1   Id=1000   Num=46, 
Name=Student4   Id=1001   Num=47]

预期产出:

Name=Student1   Id=1000   Num=1, 
Name=Student2   Id=1001   Num=2, 
Name=Student3   Id=1002   Num=3, 
Name=Student4   Id=1001   Num=4, 
Name=Student1   Id=1003   Num=45]

谢谢

3 个答案:

答案 0 :(得分:0)

您的Comparator实施不正确,因为当前对象始终等于或大于比较对象(您永远不会返回负值)。
所以对称规则不受尊重:

  

实现者必须确保sgn(x.compareTo(y))==   -sgn(y.compareTo(x))表示所有x和y。

无论如何,要删除重复项,TreeSet如果您不想对它们进行排序则不合适。

而不是覆盖equals()课程中的hashCode()Student,并在ArrayList中添加您的元素(最初位于LinkedHashSet)以保留实际订单。

final List<Student> students = new ArrayList<>();
students.add(new Student("Student1", "1000", "1"));
students.add(new Student("Student2", "1001", "2"));
...
LinkedHashSet<Student> set = new LinkedHashSet<>(students);

答案 1 :(得分:0)

你的Comparator违反了比较合同:

  

比较其订单的两个参数。当第一个参数小于,等于或大于第二个参数时,返回负整数,零或正整数。

此外,TreeSet中的添加需要log(n)(这不是很糟糕,特别是对于那些大型集合而言),如果您可以覆盖equals和{{1}这通常是一个更好的选择。

但是,如果您希望自动生成自定义比较器,或者无法/想要覆盖hashcodeequals,则可以使用hashcodecomparing函数提供了java thenComparing

Comparator

此比较器功能通常更易于使用,并且可能更不容易出错。您可以照常在Comparator<Student> studentComparator = Comparator .comparing((Student student) -> student.getId().toLowerCase()) .thenComparing((Student student) -> student.getNum().toLowerCase()); 中使用它。

然而,这个比较器不是空的安全,你需要传递TreeSet作为第二个参数来允许比较空值。并且在致电Comparator.nullsFirst(Comparator.naturalOrder())之前检查字符串。

您可以使用一些辅助方法(或者创建一个定义类似的自定义比较器):

toLowerCase()

例如,如果public static String handleCase(String str) { return str != null ? str.toLowerCase() : null; } public static <T extends Comparable<? super T>> Comparator<T> nullComparator() { return Comparator.nullsFirst(Comparator.naturalOrder()); } 是可以为空的属性,则可以使用:

num

最后,如果您想从“任何地方”访问此比较器,您可以将定义包装在比较器中,作为Comparator<Student> studentComparator = Comparator .comparing((Student student) -> handleCase(student.getId())) .thenComparing((Student student) -> handleCase(student.getNum()), nullComparator()); 字段,或final作为单例,或者作为{自定义比较器的辅助类中的{1}}字段。

答案 2 :(得分:0)

以下是您特定问题的运行代码。

学生班级

public class Student {

private String name;
private String id;
private String num;



public Student(String name, String id, String num) {
    super();
    this.name = name;
    this.id = id;
    this.num = num;
}
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;
}
public String getNum() {
    return num;
}
public void setNum(String num) {
    this.num = num;
}
@Override
public String toString() {
    return "Student [name=" + name + ", id=" + id + ", num=" + num + "]";
}

主要课程

public class RemoveDuplicate {
public static void main(String[] args) {
    final ArrayList students = new ArrayList();
    students.add(new Student("Student1", "1000", "1"));
    students.add(new Student("Student2", "1001", "2"));
    students.add(new Student("Student3", "1002", "3"));
    students.add(new Student("Student4", "1001", "4"));
    students.add(new Student("Student1", "1003", "45"));
    students.add(new Student("Student1", "1000", "46"));
    students.add(new Student("Student4", "1001", "47"));

    Set set = new TreeSet(new StudentsComparator());
    set.addAll(students);
    final ArrayList newList = new ArrayList(set);
    System.out.println(newList);
}
}
class StudentsComparator implements Comparator<Student> {
@Override
    public int compare(Student s1, Student s2) {
      if (s1.getId().compareTo(s2.getId()) == 0) 
         return s1.getName().compareTo(s2.getName());
      else 
         return s1.getId().compareTo(s2.getId());
    }
}