在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中将两者结合在一起。
我建议你去。
-
TreeSet
在这里集中关于重复删除 - 然后,一旦有了唯一的数据,就可以使用
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 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; } }