ordering funciona ejemplo como java sorting collections treeset unique

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.

  1. TreeSet aquí se concentra en la eliminación duplicada
  2. 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 utilizando Arrays.sort() y un Comparator 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).