java - funciona - En TreeSet, clasificación y unicidad de objetos personalizados basados en diferentes propiedades
treeset java ejemplo (4)
Debajo está mi clase de Estudiante
class Student implements Comparable {
String name;
int rollNo;
@Override
public int compareTo(Object obj) {
return ((Student)obj).name.compareTo(this.name);
}
}
última modificación: pero todavía no se obtiene el resultado correcto
@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);
}
}
}
Si creo un objeto de TreeSet <Student>, obtengo una lista ordenada de objetos de Estudiante basada en un nombre único y ordenada por nombre también.
Pero necesito un nombre de estudiante único en mi TreeSet <Estudiante> con orden por estudiante-rollNo.
¿Es posible con Comparator? ¿Alguien puede ayudarme? Toda sugerencia es apreciada. Gracias.
ACTUALIZACIÓN: aquí está el programa completo:
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;
}
}
Actualización: 2: Gracias a todos por sus sugerencias, todavía necesito un poco más :)
/*
* 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;
}
}
SALIDA :
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]
Amigos, lo que sea que obtuve usando dos Comparadores, ¿es posible lograr lo mismo al agregar los objetos? Primero no puedo Agregar elementos y luego usar comparador nuevo para lograr el orden deseado.
Estoy manipulando miles de valores, así que también debo considerar el rendimiento.
en TreeSet
usará el comparador mientras agrega elementos para la clasificación y verificación única,
ahora el problema es que si usa el comparador para rollo no lo tendrá ordenado por rollo no y rollo único también. no puedes tener ambas cosas juntas en treeset.
Te sugiero que vayas.
-
TreeSet
aquí se concentra en la eliminación duplicada - luego, una vez que tenga datos únicos, vaya a
ArrayList
y ordene en el orden que desee
Puede inicializar un nuevo TreeSet con un comparador diferente. - Entonces, todo lo que tiene que hacer es escribir un nuevo Comparador (implementa la interfaz java.util.Comparator), use este comparador para inicializar un nuevo TreeSet y luego agregue todos los estudiantes al conjunto.
TreeSet<Student> sortedByRollNo new TreeSet<Student>(new RollNoComparator());
sortedByRollNo.addAll(allStudents);
TreeSet<Student> sortedByY new TreeSet<Student>(new YComparator());
sortedByY.addAll(allStudents);
Cada conjunto de árboles puede tener su propio comparador para la clasificación, si no se especifica ningún comparador, entonces el conjunto de árboles usa el orden natural de los elementos establecidos.
adicional
Si solo necesita el nombre de Uniqe Students, entonces tiene dos formas:
- Implementa el comparador de una manera, que devuelve 0 si el nombre de los studens es igual (pero creo que esto es tan kinde de hack).
- Primero filtre a los estudiantes por su nombre, y luego ordénelos por rollNo,
Un poco como esto:
TreeSet<Student> sortedByRollNo new TreeSet<Student>(new RollNoComparator());
sortedByRollNo.addAll(new TreeSet<Student>(allStudends)); //this uses the native comparator to filter by uniqe name
Perdón por llegar tarde, aquí hay una solución elegante:
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;
}
}
Ordenando
La respuesta de @ralph sobre el uso de un TreeSet
con un comparador especificado es buena, TreeSet
.
Diseño
Debería envolver su concepto de una "base de datos de estudiantes" dentro de una clase que expone y documenta los comportamientos correctos, en lugar de simplemente usar una colección sin formato. Si la obtención de listas de estudiantes en órdenes particulares es un requisito de diseño, exponga los métodos (tal vez devolviendo Iterable<Student>
que digan eso. Detrás de escena, puede hacer una variedad de cosas dependiendo del patrón de uso:
- Mantenga uno o más estudiantes de clasificación y clasificación de
Set
sy yo por campos de interés. -
Arrays.sort()
in situ de arreglos in situ utilizandoArrays.sort()
y unComparator
especificado.
Ejemplo....
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) { ... }
}
Unicidad
hashCode()
sobrescribir equals()
y hashCode()
en su clase de Student
, para comparar solo el nombre del alumno. Entonces obtendrás unicidad (silenciosamente) en tu TreeSet
. Obviamente, si hace esto, debe codificar a la defensiva para verificar si studentSet.contains(newStudent)
antes de insertar newStudent
, para que newStudent
si tiene un duplicado o no.
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
}
}
Con esto en su lugar, entonces su código para insertar estudiante puede verse así:
void addNewStudent(final Student toAdd)
{
if (studentSet.contains(toAdd)) {
throw new IllegalStateException("Student with same name as "+toAdd+" already exists.");
}
studentSet.add(toAdd);
}
Su conjunto de árboles está lleno de estudiantes cuyos nombres son únicos, y su operación de agregar reporta un error si no es así. (Lanzar una excepción es solo una ruta potencial, y solo apropiada si agregar un estudiante con un nombre duplicado es REALMENTE una condición excepcional, pero no lo dijiste).