Подтвердить что ты не робот

Сортировка списка объектов по нескольким полям

У меня есть список объектов Java, которые я хочу отсортировать в соответствии с несколькими полями.

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

Можно ли использовать интерфейс Comparator или Comparable для сортировки списка в соответствии с несколькими полями? Все примеры, которые я видел, сортируются только по одному полю. Другими словами, можно сортировать по "кампусу" или "факультету" или "зданию". Я хочу сортировать по "кампусу", затем "способность", затем "строить" (как это существует в SQL: ORDER BY campus, faculty, building)

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

4b9b3361

Ответ 1

Ваш компаратор будет выглядеть так:

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

В основном он продолжает сравнивать каждый последующий атрибут вашего класса всякий раз, когда сравниваемые атрибуты равны (== 0).

Ответ 2

Да, вы абсолютно можете это сделать. Например:

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

В основном вы говорите: "Если я могу сказать, какой из них на первом месте, просто посмотрев на кампус (прежде чем они придут из разных кампусов, а кампус - это самое важное поле), я просто верну этот результат. В противном случае, я продолжу сравнивать способности. Опять же, остановитесь, если этого достаточно, чтобы рассказать им обособленно. В противном случае (если кампус и преподаватели одинаковы для обоих людей), просто используйте результат их сравнения путем построения".

Ответ 3

Если вы заранее знаете, какие поля использовать для сравнения, тогда другие люди дали правильные ответы.
Что вам может быть интересно, так это сортировать свою коллекцию, если вы не знаете во время компиляции, какие критерии применять. Представьте, что у вас есть программа, касающаяся городов:



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

где вы можете заменить имена закодированных полей именами полей, выведенными из пользовательского запроса в вашей программе.

В этом примере City.CityMultiComparator<City> представляет собой статический вложенный класс класса City, реализующий 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;
        }
    }


Вы можете добавить дополнительный уровень точности, чтобы указать для каждого поля, должна ли сортировка быть восходящей или потоковой. Я предполагаю, что решение заключается в замене объектов Field объектами класса, который вы могли бы назвать SortedField, содержащим объект Field, плюс другое поле, означающее восходящее или потоковое потомство.

Ответ 4

Вам просто нужно, чтобы ваш класс наследовал от Comparable.

затем реализуем метод compareTo, как вам нравится.

Ответ 5

Надеюсь, что это поможет:

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

Ответ 6

Вам нужно написать собственный метод compareTo(), который имеет код Java, необходимый для сравнения.

Если бы мы хотели, например, сравнить два общедоступных поля, кампус, затем факультет, мы могли бы сделать что-то вроде:

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

Это упрощено, но, надеюсь, дает вам представление. Для получения дополнительной информации обратитесь к документам Comparable и Comparator.