web-dev-qa-db-ja.com

複数のフィールドでオブジェクトのリストを並べ替える

Java複数のフィールドに従ってソートしたいオブジェクトのリストがあります。

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

ComparatorまたはComparableインターフェイスを使用して、複数のフィールドに従ってリストを並べ替えることはできますか?私が見たすべての例は、1つのフィールドのみに従ってソートされます。つまり、「キャンパス」で並べ替えることができますOR 'faculty' OR 'building'。 'キャンパス'で並べ替えてから 'faculty '、次に' building '(SQLに存在する場合:ORDER BY campus, faculty, building

この質問は 前に尋ねた だったと思いますが、受け入れられた答えがわかりません。誰かがこの答えを拡大または説明できますか?

34
sim

コンパレータは次のようになります。

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)。

61
Daniel DiPaolo

はい、絶対にこれを行うことができます。例えば:

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

基本的には、「キャンパスを見ただけで(キャンパスが異なるキャンパスから来る前で、キャンパスが最も重要な分野である)最初に来るものがわかるなら、その結果を返すだけです。それ以外の場合は、 「引き続き学部の比較を行います。繰り返しますが、それで十分に区別できる場合は停止します。それ以外の場合(キャンパスと学部が両方の人で同じである場合)は、建物ごとに比較した結果を使用します。」

34
Jon Skeet

比較に使用するフィールドを事前に知っている場合、他の人が正しい答えを出しました。
興味があるのは、コンパイル時に適用する基準がわからない場合にコレクションをソートすることです。都市を扱うプログラムがあると想像してください:



    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オブジェクトを、呼び出し可能なクラスのオブジェクトに置き換えることだと思います SortedFieldFieldオブジェクト、およびascendantまたはdescendantを意味する別のフィールドを含む。

5
Marek Stanley

お役に立てれば:

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

クラスに Comparable を継承させる必要があります。

次に、 compareTo メソッドを好きな方法で実装します。

1
Yochai Timmer

比較を実行するために必要なJavaコードを持っている独自のcompareTo()メソッドを記述する必要があります。

たとえば、キャンパスと教員の2つのパブリックフィールドを比較したい場合は、次のようにします。

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のドキュメントを参照してください。

0
mwd