在TreeSet中,排序&基于不同属性的自定义对象的唯一性

发布于 2024-10-07 15:43:26 字数 4893 浏览 0 评论 0原文

以下是我的 Student 类

class Student implements Comparable {
   String name;
   int rollNo;

   @Override
   public int compareTo(Object obj) {
        return ((Student)obj).name.compareTo(this.name);
   }
} 

最新修改:但仍然没有得到正确的结果

@Override
public int compareTo(Object obj) {
    Student s = (Student) obj;
    if (name.equals(s.name)) { // achieving uniqueness
        return 0;
    } else {
        if (rollNo < s.rollNo) {
            return -1;
        } else if (rollNo > s.rollNo) {
            return 1;
        } else {
            // this makes `name` the second ordering option.
            // names don't equal here
            return name.compareTo(s.name);
        }
    }
}

如果我创建 TreeSet对象,我将根据唯一名称和名称获取 Student 对象的排序列表。也按名字排序。

但我需要在我的 TreeSet中唯一的学生姓名按学生卷号订购。

用比较器可以吗?任何人都可以帮助我,每个建议都会受到赞赏。 谢谢。

更新:这是完整的程序:

public class Student implements Comparable {

    int rollNo;
    String name;

    Student(String n,int rno) {
        rollNo=rno;
        name=n;
    }

    /**
     * @param args
     */
    public static void main(String[] args) {

        TreeSet<Student> ts = new TreeSet<Student>();
        ts.add(new Student("bbb",2));
        ts.add(new Student("aaa",4));
        ts.add(new Student("bbb",2));
        ts.add(new Student("ccc",3));
        ts.add(new Student("aaa",1));
        ts.add(new Student("bbb",2));
        ts.add(new Student("bbb",5));

        System.out.println(ts);

    }

    @Override
    public int compareTo(Object obj) {
        Student s = (Student) obj;
        if (name.equals(s.name)) { // achieving uniqueness
            return 0;
        } else {
            if (rollNo < s.rollNo) {
                return -1;
            } else if (rollNo > s.rollNo) {
                return 1;
            } else {
                // this makes `name` the second ordering option.
                // names don't equal here
                return name.compareTo(s.name);
            }
        }
    }

    @Override
    public String toString() {
        return name + rollNo;
    }
}

更新:2:谢谢大家的建议,我还需要更多:)



/*
 * Actual scenario is having different properties,
 * So here I am just relating my actual scenario with Student class
 */
class Student implements Comparable {
    // sorting required on rollNo
    int rollNo;
    // Unique name is required
    String name;

    Student(String n, int rno) {
        rollNo = rno;
        name = n;
    }

    /**
     * 
     * @param args
     */
    public static void main(String[] args) {

        TreeSet<Student> tsName = new TreeSet<Student>();
        // here by default, order & uniqueness by name only
        tsName.add(new Student("ccc", 2));
        tsName.add(new Student("aaa", 4));
        tsName.add(new Student("ddd", 1));
        tsName.add(new Student("bbb", 3));
        tsName.add(new Student("ddd", 5));
        // output: aaa:4, bbb:3, ccc:2, ddd:1
        System.out.println(tsName);

        // creating new comparator for student RollNo
        TreeSet<Student> tsRollNo = new TreeSet<Student>(new Comparator<Student>() {
                    public int compare(Student stud1, Student stud2) {
                        return new Integer(stud1.rollNo).compareTo(stud2.rollNo);
                    }
                });
        tsRollNo.addAll(tsName);
        System.out.println(tsRollNo);
        // now got the desire output: ddd:1, ccc:2, bbb:3, aaa:4
    }

    public boolean equals(Object obj) {
        // internally not used to check equality while adding objects
        // in TreeSet
        System.out.println("equals() for " + this + " & " + ((Student) obj));
        return false;// return false/true doesn't make any sense here
    }

    @Override
    public int compareTo(Object obj) {
        Student s = (Student) obj;
        // internally inside TreeSet, compareTo is used to decide
        // whether two objects are equal or not,
        // i.e. compareTo will return 0 for same object(here student name)
        System.out.println("compareTo() for " + this + " & " + ((Student) obj));
        // achieving uniqueness
        return name.compareTo(s.name);
    }

    @Override
    public String toString() {
        return name + ":" + rollNo;
    }
}

输出

compareTo() for aaa:4 & ccc:2
compareTo() for ddd:1 & ccc:2
compareTo() for bbb:3 & ccc:2
compareTo() for bbb:3 & aaa:4
compareTo() for ddd:5 & ccc:2
compareTo() for ddd:5 & ddd:1
[aaa:4, bbb:3, ccc:2, ddd:1]
[ddd:1, ccc:2, bbb:3, aaa:4]

< b>朋友们,无论我使用两个比较器得到什么,是否有可能 添加对象时达到相同的效果? 我不能先添加元素 &然后使用新的比较器来实现所需的顺序。
我正在操纵数千个值,因此还需要考虑性能。

Below is my Student class

class Student implements Comparable {
   String name;
   int rollNo;

   @Override
   public int compareTo(Object obj) {
        return ((Student)obj).name.compareTo(this.name);
   }
} 

latest modification: but still no getting the right result

@Override
public int compareTo(Object obj) {
    Student s = (Student) obj;
    if (name.equals(s.name)) { // achieving uniqueness
        return 0;
    } else {
        if (rollNo < s.rollNo) {
            return -1;
        } else if (rollNo > s.rollNo) {
            return 1;
        } else {
            // this makes `name` the second ordering option.
            // names don't equal here
            return name.compareTo(s.name);
        }
    }
}

If I create object of TreeSet<Student>, I am getting sorted list of Student objects based on unique name & ordered by name also.

But I need unique student-name in my TreeSet<Student> with order by student-rollNo.

Is it possible with Comparator? Can anybody help me, Every suggestion is appreciated.
Thanks.

UPDATE: here is the complete program:

public class Student implements Comparable {

    int rollNo;
    String name;

    Student(String n,int rno) {
        rollNo=rno;
        name=n;
    }

    /**
     * @param args
     */
    public static void main(String[] args) {

        TreeSet<Student> ts = new TreeSet<Student>();
        ts.add(new Student("bbb",2));
        ts.add(new Student("aaa",4));
        ts.add(new Student("bbb",2));
        ts.add(new Student("ccc",3));
        ts.add(new Student("aaa",1));
        ts.add(new Student("bbb",2));
        ts.add(new Student("bbb",5));

        System.out.println(ts);

    }

    @Override
    public int compareTo(Object obj) {
        Student s = (Student) obj;
        if (name.equals(s.name)) { // achieving uniqueness
            return 0;
        } else {
            if (rollNo < s.rollNo) {
                return -1;
            } else if (rollNo > s.rollNo) {
                return 1;
            } else {
                // this makes `name` the second ordering option.
                // names don't equal here
                return name.compareTo(s.name);
            }
        }
    }

    @Override
    public String toString() {
        return name + rollNo;
    }
}

Update:2: Thank you all for your suggestions, I still need some more :)



/*
 * Actual scenario is having different properties,
 * So here I am just relating my actual scenario with Student class
 */
class Student implements Comparable {
    // sorting required on rollNo
    int rollNo;
    // Unique name is required
    String name;

    Student(String n, int rno) {
        rollNo = rno;
        name = n;
    }

    /**
     * 
     * @param args
     */
    public static void main(String[] args) {

        TreeSet<Student> tsName = new TreeSet<Student>();
        // here by default, order & uniqueness by name only
        tsName.add(new Student("ccc", 2));
        tsName.add(new Student("aaa", 4));
        tsName.add(new Student("ddd", 1));
        tsName.add(new Student("bbb", 3));
        tsName.add(new Student("ddd", 5));
        // output: aaa:4, bbb:3, ccc:2, ddd:1
        System.out.println(tsName);

        // creating new comparator for student RollNo
        TreeSet<Student> tsRollNo = new TreeSet<Student>(new Comparator<Student>() {
                    public int compare(Student stud1, Student stud2) {
                        return new Integer(stud1.rollNo).compareTo(stud2.rollNo);
                    }
                });
        tsRollNo.addAll(tsName);
        System.out.println(tsRollNo);
        // now got the desire output: ddd:1, ccc:2, bbb:3, aaa:4
    }

    public boolean equals(Object obj) {
        // internally not used to check equality while adding objects
        // in TreeSet
        System.out.println("equals() for " + this + " & " + ((Student) obj));
        return false;// return false/true doesn't make any sense here
    }

    @Override
    public int compareTo(Object obj) {
        Student s = (Student) obj;
        // internally inside TreeSet, compareTo is used to decide
        // whether two objects are equal or not,
        // i.e. compareTo will return 0 for same object(here student name)
        System.out.println("compareTo() for " + this + " & " + ((Student) obj));
        // achieving uniqueness
        return name.compareTo(s.name);
    }

    @Override
    public String toString() {
        return name + ":" + rollNo;
    }
}

OUTPUT:

compareTo() for aaa:4 & ccc:2
compareTo() for ddd:1 & ccc:2
compareTo() for bbb:3 & ccc:2
compareTo() for bbb:3 & aaa:4
compareTo() for ddd:5 & ccc:2
compareTo() for ddd:5 & ddd:1
[aaa:4, bbb:3, ccc:2, ddd:1]
[ddd:1, ccc:2, bbb:3, aaa:4]

Friends, whatever I got by using two Comparators, Is it possible to
achieve the same while adding the objects ??
I cannot first Add elements & then use new comparator to achieve the desired order.

I am manipulating thousands of values so need to consider performance also.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

巷雨优美回忆 2024-10-14 15:43:26

TreeSet 中,它将在添加元素进行排序和唯一检查时使用比较器,

现在的问题是,如果您对卷号使用比较器,您也会按卷号和唯一卷号对其进行排序。你不能在树集中同时拥有两者。

我建议你去。

  1. TreeSet 在这里,您专注于重复删除,
  2. 然后一旦您拥有唯一的数据,就可以使用 ArrayList 并按照您想要的任何顺序对其进行排序

in TreeSet It will use comparator while adding elements for sorting and unique check,

now the problem is if you use comparator for roll no you will have it sorted by roll no and unique roll nos too. you can't have both together in treeset.

I would suggest you to go for.

  1. TreeSet here you concentrate about duplicate removal
  2. then once you have unique data go for ArrayList and sort it in any order you want
终止放荡 2024-10-14 15:43:26

订购

@ralph 的答案 使用具有指定比较器的 TreeSet 是一个很好的选择,请使用它。

设计

您应该将“学生数据库”的概念包装在一个类中,该类公开并记录正确的行为,而不是仅仅使用原始集合。如果按特定顺序获取学生列表是设计要求,请公开方法(可能返回表示这一点的 Iterable)。在幕后,您可以根据使用模式执行各种操作:

  • 维护一个或多个集合和/或地图,按感兴趣的领域对学生进行排序/索引。
  • 使用 Arrays.sort() /code> 和指定的 Comparator。...

唯一

final class StudentTable {
   private static final Comparator<Student> studentRollNoComparator = ...;
   private final SortedSet<Student> sortedByRollNo = 
      new TreeSet<Student>(studentRollNoComparator);

   public Iterable<Student> studentsOrderedByRollNo()
   {
      return sortedByRollNo;
   } 

   //see below
   public void addStudent(final Student foo) { ... }
}

您需要重写 equals()hashCode()。 >Student 类,仅比较学生姓名,然后您将在 TreeSet 中获得唯一性,显然,如果您这样做,则需要进行防御性编码以进行检查。在插入 newStudent 之前查看是否 studentSet.contains(newStudent) ,这样您就知道是否有重复项

final class Student implements Comparable {
   ...

   @Override
   public boolean equals(Object o)
   {
      return o!=null &&  
             o (instanceof Student) &&
             ((Student)o).name.equals(this.name);
   }

   @Override
   public int hashCode()
   {
      return name.hashCode();  // good enough for this purpose
   } 
}

,然后您的代码就可以了 。插入学生可能看起来像:

void addNewStudent(final Student toAdd)
{
   if (studentSet.contains(toAdd)) { 
      throw new IllegalStateException("Student with same name as "+toAdd+" already exists.");
   }

   studentSet.add(toAdd);
}

然后,您的树集中充满了姓名唯一的学生,如果不是,您的添加操作将报告失败。 (抛出异常只是一种潜在的途径,并且仅当添加具有重复姓名的学生实际上是一种异常情况时才适用,但您没有说。)

Ordering

The answer by @ralph on using a TreeSet with a specified comparator is a good one, use that.

Design

You should wrap your concept of a "student database" inside a class that exposes and documents the correct behaviors, rather than just using a raw collection. If obtaining lists of students in particular orders is a design requirement, expose methods (perhaps returning Iterable<Student> that say that. Behind the scenes, you can do a variety of things depending on the usage pattern:

  • Maintain one or more Sets and or Maps sorting/indexing students by fields of interest.
  • On-demand in-place array sort using Arrays.sort() and a specified Comparator.

Example....

final class StudentTable {
   private static final Comparator<Student> studentRollNoComparator = ...;
   private final SortedSet<Student> sortedByRollNo = 
      new TreeSet<Student>(studentRollNoComparator);

   public Iterable<Student> studentsOrderedByRollNo()
   {
      return sortedByRollNo;
   } 

   //see below
   public void addStudent(final Student foo) { ... }
}

Uniqueness

You need to override equals() and hashCode() on your Student class, to compare only the student name. Then you'll get uniqueness (silently) in your TreeSet. Obviously, if you do this, you need to code defensively to check to see if studentSet.contains(newStudent) before inserting newStudent, so you'll KNOW whether you've got a duplicate or not.

final class Student implements Comparable {
   ...

   @Override
   public boolean equals(Object o)
   {
      return o!=null &&  
             o (instanceof Student) &&
             ((Student)o).name.equals(this.name);
   }

   @Override
   public int hashCode()
   {
      return name.hashCode();  // good enough for this purpose
   } 
}

With this in place, then your code to insert student can look like:

void addNewStudent(final Student toAdd)
{
   if (studentSet.contains(toAdd)) { 
      throw new IllegalStateException("Student with same name as "+toAdd+" already exists.");
   }

   studentSet.add(toAdd);
}

Your treeset is then full of students whose names are unique, and your add operation reports a failure if not. (Throwing an exception is just one potential route, and only appropriate if adding a student with a duplicate name is ACTUALLY an exceptional condition, but you didn't say.)

ゃ懵逼小萝莉 2024-10-14 15:43:26

您可以使用不同的比较器初始化新的 TreeSet。 - 所以你所要做的就是编写一个新的Comparator(实现java.util.Comparator接口),使用这个比较器初始化一个新的TreeSet,然后将所有学生添加到该集合中。

TreeSet<Student> sortedByRollNo new TreeSet<Student>(new RollNoComparator());
sortedByRollNo.addAll(allStudents);

TreeSet<Student> sortedByY new TreeSet<Student>(new YComparator());
sortedByY.addAll(allStudents);

每个树集可以有自己的比较器进行排序,如果没有指定比较器,则树集使用集合元素的自然排序。

添加

如果你只需要名字uniqe Students,那么你有两种方法:

  • 以一种方式实现比较器,如果学生的名字相等,它返回0(但我相信这是如此善良)黑客)。
  • 首先按名字过滤学生,然后按rollNo排序,

有点像这样:

TreeSet<Student> sortedByRollNo new TreeSet<Student>(new RollNoComparator());
sortedByRollNo.addAll(new TreeSet<Student>(allStudends)); //this uses the native comparator to filter by uniqe name

You can initialize a new TreeSet with an different comparator. - So all you have to do, is to write an new Comparator (implements java.util.Comparator interface), use this comparator to initialize the a new TreeSet and then add all students to the set.

TreeSet<Student> sortedByRollNo new TreeSet<Student>(new RollNoComparator());
sortedByRollNo.addAll(allStudents);

TreeSet<Student> sortedByY new TreeSet<Student>(new YComparator());
sortedByY.addAll(allStudents);

Each Tree Set can have its own comparator for sorting, if no comparator is specifed, then the Tree Set uses the natural ordering of the set elements.

added

If you need only the name uniqe Students, then you have two ways:

  • Implement the comparator in a way, that it returns 0 if the name of the studens is equals (but i belive this is so kinde of hack).
  • First filter the students by name, and then sort them by rollNo,

A bit like this:

TreeSet<Student> sortedByRollNo new TreeSet<Student>(new RollNoComparator());
sortedByRollNo.addAll(new TreeSet<Student>(allStudends)); //this uses the native comparator to filter by uniqe name
[浮城] 2024-10-14 15:43:26

抱歉来晚了,这是一个优雅的解决方案:

    public class OwnSortedList<T> extends TreeSet<T> {

    private static final long serialVersionUID = 7109828721678745520L;


    public OwnSortedList(Comparator<T> levelScoreComparator) {
        super(levelScoreComparator);
    }


    public boolean add(T e) {
        boolean existsElement = false;

        Iterator<T> it = iterator();
        while(it.hasNext() && !existsElement){
            T nextElement = it.next();
            if(nextElement.equals(e)){
                // Element found
                existsElement = true;
                Comparator<? super T> comparator = comparator();
                int compare = comparator.compare(nextElement, e);
                if(compare > 0){
                    remove(nextElement);
                    super.add(e);
                    //element added so return true
                    return true;
                }

            }
        }

        if(!existsElement){
            super.add(e);
        }

        return false;
    }
}

Sorry for being to late here, here is an elegant solution:

    public class OwnSortedList<T> extends TreeSet<T> {

    private static final long serialVersionUID = 7109828721678745520L;


    public OwnSortedList(Comparator<T> levelScoreComparator) {
        super(levelScoreComparator);
    }


    public boolean add(T e) {
        boolean existsElement = false;

        Iterator<T> it = iterator();
        while(it.hasNext() && !existsElement){
            T nextElement = it.next();
            if(nextElement.equals(e)){
                // Element found
                existsElement = true;
                Comparator<? super T> comparator = comparator();
                int compare = comparator.compare(nextElement, e);
                if(compare > 0){
                    remove(nextElement);
                    super.add(e);
                    //element added so return true
                    return true;
                }

            }
        }

        if(!existsElement){
            super.add(e);
        }

        return false;
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文