【问题标题】:java: Comparator and Treeset to remove duplicatesjava:比较器和树集删除重复项
【发布时间】:2023-03-15 20:14:02
【问题描述】:

我有一个这样的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)

但是我怎样才能只使用一个比较器和一个树集来做同样的事情呢?

感谢您的帮助

更新:

感谢大家的回答,但读完之后我不知道这是否是解决实际问题的正确方法。

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

您可以修改课程,但我想知道这种方法是否可以解决实际问题。

如果这种方法是正确的,从你的问题来看,我看到不修改类是不可能只使用一个比较器

谢谢

【问题讨论】:

  • 添加equals()hashCode()A 是不是一个选项?扩展A 也不行吗?
  • @BaluC 我更新了问题

标签: java duplicates comparator treeset


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    你不能,而且我不清楚你要做什么是明确定义的。

    您是否知道您当前的方法既取决于添加元素的顺序,也取决于您是先检查 field1 还是 field2 是否有重复项?想象一下,你有这些 A 类对象:

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

    首先检查 field1 会给出结果 [ab][ab, cd],具体取决于添加的顺序。

    首先检查 field2 会给出结果 [cb][ab, cd],具体取决于添加的顺序。

    这是非常奇怪的行为。这是你想要的吗?在一般情况下,我认为不可能使用单个 TreeSet 和 Comparator 来重现这一点。

    【讨论】:

    • @res1,您的更新没有说明问题。可以假设“a”是名称,“c”是名称,“b”是电话号码,“d”是电话号码。有时使用这三对你只会在“b”处叫“a”,根本不会叫“c”,也根本不会叫数字“d”。那是你的意图吗?如果不是,请说明您希望在这种情况下发生什么。
    • 看看你的测试用例这不是我想要的,我想得到 [ab, cd] 作为结果而不是 [ab]。
    【解决方案3】:
    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;
    }
    

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

    【讨论】:

    • 这假定equals()hashCode()A 上实现。
    • @BalusC 我知道你是如何破译的:A extends Comparable&lt;?&gt;
    • 啊,我错过了那部分。好吧,我知道修改A 不是一种选择。我只是不明白在这个例子中HashSet 是如何必要的。
    • A 没有声明为final,所以他可以extend A 来代替。
    • 扩展A 涉及到使用类的代码的更多更改。如果它也被某些 3rd 方 API 在内部使用,那么它可能不是一个可行的选择。
    【解决方案4】:

    如果您打算进行两级排序(第一:电话号码和第二:姓名),那么您可以使用以下代码,其中将针对两个字段(字段 1 和字段 2)进行重复检查。由于我们已经对这两个字段使用了 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;
    }
    

    }

    【讨论】:

      【解决方案5】:
      public class RemoveDuplicate {
      
      public static void main(String[] args) {
      
          final ArrayList<Student> students = new ArrayList<Student>();
      
          Set<Student> set = new TreeSet<Student>();
          Student[] starr = new Student[6];
          starr[0] = new Student("Student1", "1005");
          starr[1] = new Student("Student2", "1004");
          starr[2] = new Student("Student3", "1003");
          starr[3] = new Student("Student6", "1002");
          starr[4] = new Student("Student5", "1001");
          starr[5] = new Student("Student6", "1000");
      
          Arrays.sort(starr, Student.StudentIdComparator);
          for (Student s : starr) {
              students.add(s);
          }
      
          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);
      }}
      

      【讨论】:

        【解决方案6】:
         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());
           }
        

        【讨论】:

        • 按ID排序,按名称去重复
        猜你喜欢
        • 2011-11-05
        • 2015-07-15
        • 1970-01-01
        • 1970-01-01
        • 2011-12-18
        • 2017-06-09
        • 2014-12-16
        • 2017-12-31
        相关资源
        最近更新 更多