В TreeSet, сортировка и уникальность пользовательских объектов на основе различных свойств - PullRequest
10 голосов
/ 15 декабря 2010

Ниже мой класс ученика

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 с заказом по ученику. № 1011 *

Возможно ли это с Comparator? Кто-нибудь может мне помочь, Каждое предложение приветствуется. Спасибо.

ОБНОВЛЕНИЕ: вот полная программа:

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;
    }
}

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]

Друзья, все, что я получил, используя два компаратора, можно ли добиться того же при добавлении объектов ?? Я не могу сначала добавить элементы, а затем использовать новый компаратор для достижения желаемого порядка.
Я манипулирую тысячами значений, поэтому необходимо учитывать и производительность.

Ответы [ 4 ]

5 голосов
/ 16 декабря 2010

in TreeSet Будет использоваться компаратор при добавлении элементов для сортировки и уникальной проверки,

Теперь проблема в том, что если вы используете компаратор для броска нет, он будет отсортирован по номеру броска и уникальным номерам броска. вы не можете иметь и то и другое в древовидной структуре.

Я бы предложил тебе пойти.

  1. TreeSet здесь вы сосредоточены на удалении дубликатов
  2. затем, как только у вас появятся уникальные данные, перейдите к ArrayList и отсортируйте их в любом порядке
4 голосов
/ 16 декабря 2010

Заказ

Хороший ответ от @ ralph на использовании TreeSet с указанным компаратором.

Дизайн

Вы должны обернуть свою концепцию «базы данных учеников» внутри класса, который демонстрирует и документирует правильное поведение, а не просто использует необработанную коллекцию. Если получение списков учащихся по определенным заказам является требованием к дизайну, предоставьте методы (возможно, возвращающие Iterable<Student>, которые говорят это. За кулисами вы можете делать различные вещи в зависимости от схемы использования:

  • Поддержка одного или нескольких Set s и / или Maps сортировка / индексация учащихся по интересующим областям.
  • Сортировка массивов по запросу с использованием Arrays.sort() и указанного Comparator.
* * Пример 1 022 .... * * тысяча двадцать-три
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) { ... }
}

1026 * единственность * Вам нужно переопределить equals() и hashCode() в вашем Student классе, чтобы сравнить только имя ученика. Тогда вы получите уникальность (тихо) в вашем TreeSet. Очевидно, что если вы сделаете это, вам нужно защищаться от кода, чтобы проверить, если studentSet.contains(newStudent) перед вставкой 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); } В вашем наборе деревьев полно учеников, чьи имена уникальны, и ваша операция добавления сообщает об ошибке, если нет. (Бросок исключения - это только один из возможных путей, и он подходит только в том случае, если добавление учащегося с повторяющимся именем на самом деле является исключительным условием, но вы не сказали.)

1 голос
/ 15 декабря 2010

Вы можете инициализировать новый TreeSet с другим компаратором.- Итак, все, что вам нужно сделать, это написать новый компаратор (реализует интерфейс 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
0 голосов
/ 02 августа 2013

Извините за опоздание, вот элегантное решение:

    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;
    }
}
...