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

以下是我的学生class

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 { // this makes `name` the second ordering option. // names don't equal here return name.compareTo(s.name); } } } 

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

但是我需要在我的TreeSet 中使用student-rollNo命令的唯一学生名。

比较器可以吗? 任何人都可以帮助我,每个建议都表示赞赏。 谢谢。

更新:这是完整的程序:

 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 ts = new TreeSet(); 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 { // 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 tsName = new TreeSet(); // 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 tsRollNo = new TreeSet(new Comparator() { 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, // ie 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] 

朋友,无论我使用两个比较器得到什么,是否有可能在添加对象时实现相同的目标? 我不能先添加元素然后使用新的比较器来实现所需的顺序。
我正在操纵成千上万的值,所以也需要考虑性能。

TreeSet它将使用比较器,同时添加用于排序和唯一检查的元素,

现在的问题是,如果你使用比较器滚动否,你将按照滚动否和唯一滚动nos进行排序。 你不能在treeset中将两者结合在一起。

我建议你去。

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

订购

@ralph对使用带有指定比较器的TreeSet的答案很好,使用它。

设计

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

  • 按照感兴趣的字段维护一个或多个Set和/或Maps排序/索引学生。
  • 使用Arrays.sort()和指定的Comparator进行按需就地数组排序。

例….

 final class StudentTable { private static final Comparator studentRollNoComparator = ...; private final SortedSet sortedByRollNo = new TreeSet(studentRollNoComparator); public Iterable studentsOrderedByRollNo() { return sortedByRollNo; } //see below public void addStudent(final Student foo) { ... } } 

唯一性

您需要在Student类上覆盖equals()hashCode() ,以仅比较学生姓名。 然后,您将在TreeSet获得唯一性(静默)。 显然,如果你这样做,你需要进行防御性newStudent ,以便在插入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); } 

然后,您的treeset中充满了名称唯一的学生,如果没有,则添加操作会报告失败。 (抛出exception只是一条潜在的路线,只有在添加具有重复名称的学生时才适用,这是特殊条件,但您没有说。)

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

 TreeSet sortedByRollNo new TreeSet(new RollNoComparator()); sortedByRollNo.addAll(allStudents); TreeSet sortedByY new TreeSet(new YComparator()); sortedByY.addAll(allStudents); 

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

添加

如果您只需要名称uniqe Students,那么您有两种方式:

  • 以某种方式实现比较器,如果studens的名称相等则返回0(但我相信这是hack的kinde)。
  • 首先按名称过滤学生,然后按rollNo对其进行排序,

有点像这样:

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

对不起,到这里来晚了,这是一个优雅的解决方案:

  public class OwnSortedList extends TreeSet { private static final long serialVersionUID = 7109828721678745520L; public OwnSortedList(Comparator levelScoreComparator) { super(levelScoreComparator); } public boolean add(T e) { boolean existsElement = false; Iterator it = iterator(); while(it.hasNext() && !existsElement){ T nextElement = it.next(); if(nextElement.equals(e)){ // Element found existsElement = true; Comparator 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; } }