2011-07-27 23 views
25

Mam listę obiektów Java, które chcę posortować według więcej niż jednego pola.Sortowanie listy obiektów według wielu pól

public class graduationCeremony { 
    String campus; 
    String faculty; 
    String building; 
} 

Czy jest możliwe użycie lub interfejsu ComparatorComparable aby posortować listę według wielu pól? Wszystkie przykłady, które widziałem, sortują według tylko jednego pola. Innymi słowy, można sortować według "kampusu" LUB "wydziału" LUB "budynku". Chcę sortować według "kampusu", a następnie "wydziału", a następnie "budynku" (tak jak istnieje w SQL: ORDER BY campus, faculty, building)

Myślę, że to pytanie było asked before, ale nie rozumiem zaakceptowanej odpowiedzi. Czy ktoś może rozwinąć lub zilustrować tę odpowiedź?

+1

Druga odpowiedź na to pytanie jest dobrą ilustracją. –

+0

Czy ta pomoc: http://stackoverflow.com/questions/1206073/sorting--collection-of-objects – jjnguy

+2

@sim, To dlaczego nie poświęcasz czasu na zrozumienie, zamiast łowić kod? – Moonbeam

Odpowiedz

48

Twój komparatora będzie wyglądać następująco:

public class GraduationCeremonyComparator implements Comparator<GraduationCeremony> { 
    public int compare(GraduationCeremony o1, GraduationCeremony o2) { 
     int value1 = o1.campus.compareTo(o2.campus); 
     if (value1 == 0) { 
      int value2 = o1.faculty.compareTo(o2.faculty); 
      if (value2 == 0) { 
       return o1.building.compareTo(o2.building); 
      } else { 
       return value2; 
      } 
     } 
     return value1; 
    } 
} 

Zasadniczo nadal porównując każdy kolejny atrybut swojej klasie, gdy w porównaniu atrybuty tej pory są równe (== 0) .

+0

Dzięki. Twoje wyjaśnienie pomogło groszowi spaść. Mam jaśniejsze zrozumienie użycia metody compare() teraz, której nie miałem wcześniej. – sim

+1

nie zapomnij o sprawdzeniach zerowych. Wiersz "int value1 = o1.campus.compareTo (o2.campus);" rzuci wyjątek NullPointerException, jeśli o1 ma wartość null –

0

Hope this helps:

import java.util.ArrayList; 
import java.util.Collections; 
import java.util.Comparator; 
import java.util.Iterator; 

class Person implements Comparable { 
    String firstName, lastName; 

    public Person(String f, String l) { 
    this.firstName = f; 
    this.lastName = l; 
    } 

    public String getFirstName() { 
    return firstName; 
    } 

    public String getLastName() { 
    return lastName; 
    } 

    public String toString() { 
    return "[ firstname=" + firstName + ",lastname=" + lastName + "]"; 
    } 

    public int compareTo(Object obj) { 
    Person emp = (Person) obj; 
    int deptComp = firstName.compareTo(emp.getFirstName()); 

    return ((deptComp == 0) ? lastName.compareTo(emp.getLastName()) : deptComp); 
    } 

    public boolean equals(Object obj) { 
    if (!(obj instanceof Person)) { 
     return false; 
    } 
    Person emp = (Person) obj; 
    return firstName.equals(emp.getFirstName()) && lastName.equals(emp.getLastName()); 
    } 
} 

class PersonComparator implements Comparator<Person> { 
    public int compare(Person emp1, Person emp2) { 
    int nameComp = emp1.getLastName().compareTo(emp2.getLastName()); 
    return ((nameComp == 0) ? emp1.getFirstName().compareTo(emp2.getFirstName()) : nameComp); 
    } 
} 

public class Main { 
    public static void main(String args[]) { 
    ArrayList<Person> names = new ArrayList<Person>(); 
    names.add(new Person("E", "T")); 
    names.add(new Person("A", "G")); 
    names.add(new Person("B", "H")); 
    names.add(new Person("C", "J")); 

    Iterator iter1 = names.iterator(); 
    while (iter1.hasNext()) { 
     System.out.println(iter1.next()); 
    } 
    Collections.sort(names, new PersonComparator()); 
    Iterator iter2 = names.iterator(); 
    while (iter2.hasNext()) { 
     System.out.println(iter2.next()); 
    } 
    } 
} 
29

Tak, absolutnie możesz to zrobić. Na przykład:

public class PersonComparator implements Comparator<Person> 
{ 
    public int compare(Person p1, Person p2) 
    { 
     // Assume no nulls, and simple ordinal comparisons 

     // First by campus - stop if this gives a result. 
     int campusResult = p1.getCampus().compareTo(p2.getCampus()); 
     if (campusResult != 0) 
     { 
      return campusResult; 
     } 

     // Next by faculty 
     int facultyResult = p1.getFaculty().compareTo(p2.getFaculty()); 
     if (facultyResult != 0) 
     { 
      return facultyResult; 
     } 

     // Finally by building 
     return p1.getBuilding().compareTo(p2.getBuilding()); 
    } 
} 

Zasadniczo mówisz: „Jeśli mogę powiedzieć, który z nich jest na pierwszym miejscu po prostu patrząc na kampusie (zanim one pochodzić z różnych uczelniach, a kampus jest najważniejszym pola), a następnie I "Po prostu zwrócę ten wynik, w przeciwnym razie dalej będę porównywał wydziały, ponownie przestań, jeśli to wystarczy, aby je odróżnić." W przeciwnym razie (jeśli kampus i wydział są takie same dla obu osób) po prostu skorzystaj z wyniku porównania je budując. "

+0

Elegancka implementacja. – Gravity

+2

czytelność ... to powinna być poprawna odpowiedź! – BBaker

1

Wystarczy, że klasa odziedziczy po Comparable.

następnie zastosować metodę compareTo w sposób jaki lubisz.

0

Musisz napisać własną metodę compareTo(), która ma kod Java potrzebny do wykonania porównania.

Gdybyśmy chcieli na przykład porównać dwa pola publicznych Campus, a następnie wydział, możemy zrobić coś takiego:

int compareTo(GraduationCeremony gc) 
{ 
    int c = this.campus.compareTo(gc.campus); 

    if(c != 0) 
    { 
     //sort by campus if we can 
     return c; 
    } 
    else 
    { 
     //campus equal, so sort by faculty 
     return this.faculty.compareTo(gc.faculty); 
    } 
} 

To jest uproszczony, ale mam nadzieję, że daje wyobrażenie. Aby uzyskać więcej informacji, zapoznaj się z dokumentami Comparable and Comparator.

4

Jeśli wiesz z góry, które pola użyć do porównania, inne osoby udzieliły poprawnych odpowiedzi.
Co może Cię zainteresować, to sortowanie kolekcji w przypadku, gdy nie wiesz podczas kompilacji, jakie kryteria zastosować. Wyobraź masz program do czynienia z miast:



    protected Set<City> cities; 
    (...) 
    Field temperatureField = City.class.getDeclaredField("temperature"); 
    Field numberOfInhabitantsField = City.class.getDeclaredField("numberOfInhabitants"); 
    Field rainfallField = City.class.getDeclaredField("rainfall"); 
    program.showCitiesSortBy(temperatureField, numberOfInhabitantsField, rainfallField); 
    (...) 
    public void showCitiesSortBy(Field... fields) { 
     List<City> sortedCities = new ArrayList<City>(cities); 
     Collections.sort(sortedCities, new City.CityMultiComparator(fields)); 
     for (City city : sortedCities) { 
      System.out.println(city.toString()); 
     } 
    } 

gdzie można wymienić ciężko kodowane nazwy pól, których autorem nazwy pól wyprowadzona z prośbą użytkownika w programie.

W tym przykładzie City.CityMultiComparator<City> jest statyczną zagnieżdżona klasa klasie City realizacji Comparator:



    public static class CityMultiComparator implements Comparator<City> { 
     protected List<Field> fields; 

     public CityMultiComparator(Field... orderedFields) { 
      fields = new ArrayList<Field>(); 
      for (Field field : orderedFields) { 
       fields.add(field); 
      } 
     } 

     @Override 
     public int compare(City cityA, City cityB) { 
      Integer score = 0; 
      Boolean continueComparison = true; 
      Iterator itFields = fields.iterator(); 

      while (itFields.hasNext() && continueComparison) { 
       Field field = itFields.next(); 
       Integer currentScore = 0; 
       if (field.getName().equalsIgnoreCase("temperature")) { 
        currentScore = cityA.getTemperature().compareTo(cityB.getTemperature()); 
       } else if (field.getName().equalsIgnoreCase("numberOfInhabitants")) { 
        currentScore = cityA.getNumberOfInhabitants().compareTo(cityB.getNumberOfInhabitants()); 
       } else if (field.getName().equalsIgnoreCase("rainfall")) { 
        currentScore = cityA.getRainfall().compareTo(cityB.getRainfall()); 
       } 
       if (currentScore != 0) { 
        continueComparison = false; 
       } 
       score = currentScore; 
      } 

      return score; 
     } 
    } 


Możesz dodać dodatkową warstwę precyzją, aby określić, na każde pole, czy sortowanie powinno być rosnąco czy potomkiem. Chyba rozwiązaniem jest zastąpienie Field obiektów przez obiekty klasy można nazwać SortedField, zawierający Field obiektu, plus kolejne pole oznacza Ascendent lub potomek.

Powiązane problemy