web-dev-qa-db-ja.com

ComparableとComparatorを使用する場合

フィールドで並べ替える必要があるオブジェクトのリストがあります(スコアなど)。あまり考えずに、Comparatorを実装する新しいクラスを作成しました。これはタスクを実行し、機能します。

これを振り返ってみると、Comparatorを実装する新しいクラスを作成するのではなく、代わりに私のクラスにComparableを実装させる必要があるのか​​と思っています。スコアは、オブジェクトが注文される唯一のフィールドです。

  1. 私が実践として受け入れたことは何ですか?

  2. 適切なアプローチは、「最初にクラスにComparableを実装させ(自然順序付けのために)、代替フィールドの比較が必要な場合、Comparatorを実装する新しいクラスを作成する」ですか?

  3. 上記の(2)が真である場合、クラスにComparableを実装させた後にのみComparatorを実装する必要があるということですか? (元のクラスを所有していると仮定します)。

104
pkrish

クラスをソートするための明確で自然な方法である場合、オブジェクトはComparableを実装する必要があり、クラスをソートする必要がある人は通常、そのようにしたいでしょう。

ただし、並べ替えがクラスの異常な使用である場合、または並べ替えが特定のユースケースにのみ意味がある場合は、Comparatorの方が適しています。

別の言い方をすれば、クラス名を指定すると、同等のものがどのようにソートされるかが明確ですか、またはjavadocを読むことに頼らなければなりませんか?後者の場合、将来のすべてのソートのユースケースでコンパレータが必要になる可能性が高く、その時点で、comparableの実装はクラスのユーザーを遅くする可能性があり、スピードを上げることはできません。

76
Yishai

問題のオブジェクトのdefault(自然)順序付け動作を定義する場合は、 Comparable を使用します。実際には、このためにオブジェクトの技術的または自然な(データベース?)識別子を使用します。

external controllable順序付け動作を定義する場合は、 Comparator を使用します。これにより、デフォルトの順序付け動作をオーバーライドできます。

123
BalusC

Comparableを使用します。

  • オブジェクトがコントロール内にある場合。
  • 比較動作が主な比較動作である場合。

Comparatorを使用します。

  • オブジェクトがコントロール外にあり、Comparableを実装できない場合。
  • デフォルトの動作(Comparableで指定)とは異なる動作を比較する場合。
54
Bozho

Comparable -Java.lang.Comparable: int compareTo(Object o1)

比較可能なオブジェクトは、それ自体を別のオブジェクトと比較できます。クラスをインスタンスを比較できるようにするには、クラス自体がJava.lang.Comparableインターフェースを実装する必要があります。

  • 現在のオブジェクトと提供されたオブジェクトを比較できます。
  • これを使用することにより、インスタンスのプロパティに基づいてonly one sort sequenceを実装できます。 EX:Person.id
  • String、Wrapperクラス、Date、Calendarなどの定義済みクラスの一部には、Comparableインターフェイスが実装されています。

Comparator -Java.util.Comparator: int compare(Object o1, Object o2)

コンパレータオブジェクトは、2つの異なるオブジェクトを比較できます。クラスはインスタンスを比較していませんが、他のクラスのインスタンスを比較しています。このコンパレータクラスは、Java.util.Comparatorインターフェイスを実装する必要があります。

  • 同じタイプの2つのオブジェクトを比較できます。
  • これを使用することで、インスタンスプロパティに基づいてmany sort sequenceを実装し、それぞれに名前を付けることができます。 EX:Person.id, Person.name, Person.age
  • カスタマイズされたソートのために事前定義されたクラスにComparatorインターフェースを実装できます。

例:

public class Employee implements Comparable<Employee> {

    private int id;
    private String name;
    private int age;
    private long salary;

    // Many sort sequences can be created with different names.
    public static Comparator<Employee> NameComparator = new Comparator<Employee>() {         
        @Override
        public int compare(Employee e1, Employee e2) {
            return e1.getName().compareTo(e2.getName());
        }
    };
    public static Comparator<Employee> idComparator = new Comparator<Employee>() {       
        @Override
        public int compare(Employee e1, Employee e2) {
            return Integer.valueOf(e1.getId()).compareTo(Integer.valueOf(e2.getId()));
        }
    };

    public Employee() { }
    public Employee(int id, String name, int age, long salary){
        this.id = id;
        this.name = name;
        this.age = age;
        this.salary = salary;
    }
    // setters and getters.

    // Only one sort sequence can be created with in the class.
    @Override
    public int compareTo(Employee e) {
    //return Integer.valueOf(this.id).compareTo(Integer.valueOf(e.id));
    //return Character.toString(this.name.charAt(0)).compareToIgnoreCase(Character.toString(e.name.charAt(0)));
        if (this.id > e.id) {
            return 1;
        }else if(this.id < e.id){
            return -1;
        }else {
            return Character.toString(this.name.charAt(0)).compareToIgnoreCase(Character.toString(e.name.charAt(0)));
        }

    }   

    public static void main(String[] args) {

        Employee e1 = new Employee(5, "Yash", 22, 1000);
        Employee e2 = new Employee(8, "Tharun", 24, 25000);

        List<Employee> list = new ArrayList<Employee>();
        list.add(e1);
        list.add(e2);
        Collections.sort(list); // call @compareTo(o1)
        Collections.sort(list, Employee.nameComparator); // call @compare (o1,o2)
        Collections.sort(list, Employee.idComparator); // call @compare (o1,o2)
    }
}
  • カスタマイズされたソートでは、コンパレータ@compare(o1、o2)を使用し、他のシナリオでは同等の@compareTo(o1)を使用します。複数のフィールドをソートする場合はコードを変更せずにコンパレータを使用します。

Java 8 Lambda:Comparator については、私の投稿を参照してください。

20
Yash

Comparatorは、同等の機能に加えて、さらに多くの機能を備えています。

| | Comparable | Comparator ._______________________________________________________________________________ Is used to allow Collections.sort to work | yes | yes Can compare multiple fields | yes | yes Lives inside the class you’re comparing and serves | | as a “default” way to compare | yes | yes Can live outside the class you’re comparing | no | yes Can have multiple instances with different method names | no | yes Input arguments can be a list of | just Object| Any type Can use enums | no | yes

次のように、匿名クラスとしてコンパレータを使用するための最良のアプローチを見つけました。

private static void sortAccountsByPriority(List<AccountRecord> accounts) {
    Collections.sort(accounts, new Comparator<AccountRecord>() {

        @Override
        public int compare(AccountRecord a1, AccountRecord a2) {
            return a1.getRank().compareTo(a2.getRank());
        }
    });
}

並べ替えを計画しているクラス内で、このようなメソッドの複数のバージョンを作成できます。だからあなたは持つことができます:

  • sortAccountsByPriority
  • sortAccountsByType
  • sortAccountsByPriorityAndType

    等...

現在、これらの並べ替えメソッドはどこでも使用でき、コードを再利用できます。これにより、同等のものに加えて、さらに多くのものが得られます。したがって、同等のものを使用する理由はまったくありません。

9
user2773898

同じクラスのインスタンスを比較する場合は、Comparableを使用する必要があります。

コンパレータを使用して、異なるクラスのインスタンスを比較できます。

Comparableは、オブジェクトの自然な順序を定義する必要があるクラスによって実装されます。 StringのようにComparableを実装します。

別の並べ替え順序が必要な場合は、コンパレータを実装し、2つのインスタンスを比較する独自の方法を定義できます。

9
Devang Paliwal

私は言うだろう:

  • 比較が直観的である場合、必ずComparableを実装します
  • 比較が直観的であるかどうかが不明な場合は、より明示的であり、コードを維持する必要のある貧しい魂にとってより明確であるため、コンパレータを使用します
  • 複数の直感的な比較が可能な場合は、比較するクラスのファクトリメソッドによってビルドする可能性のあるComparatorを使用します。
  • 比較が特別な目的である場合は、コンパレータを使用します
8
extraneon

オブジェクトの並べ替えを自然な順序に基づいて行う必要がある場合はComparableを使用しますが、異なるオブジェクトの属性に対して並べ替えを行う必要がある場合は、JavaのComparatorを使用します。

ComparableとComparatorの主な違い:

+------------------------------------------------------------------------------------+
¦               Comparable                ¦                Comparator                ¦
¦-----------------------------------------+------------------------------------------¦
¦ Java.lang.Comparable                    ¦ Java.util.Comparator                     ¦
¦-----------------------------------------+------------------------------------------¦
¦ int objOne.compareTo(objTwo)            ¦ int compareTo(objOne, objTwo)            ¦
¦-----------------------------------------+------------------------------------------¦
¦ Negative, if objOne < objTwo            ¦ Same as Comparable                       ¦
¦ Zero,  if objOne == objTwo              ¦                                          ¦
¦ Positive,  if objOne > objTwo           ¦                                          ¦
¦-----------------------------------------+------------------------------------------¦
¦ You must modify the clas whose          ¦ You build a class separate from to sort. ¦
¦ instances you want to sort.             ¦ the class whose instances you want       ¦
¦-----------------------------------------+------------------------------------------¦
¦ Only one sort sequemce can be created   ¦ Many sort sequences can be created       ¦
¦-----------------------------------------+------------------------------------------¦
¦ Implemented frequently in the API by:   ¦ Meant to be implemented to sort          ¦
¦ String, Wrapper classes, Date, Calandar ¦ instances of third-party classes.        ¦
+------------------------------------------------------------------------------------+
5
  • クラスの作成時に、ソートのユースケースが1つしかない場合は、Comparableを使用します。
  • ソートの戦略が複数ある場合のみ、コンパレータを実装します。
4
fabrizioM

以下のポイントは、Comparableを使用する状況と、Comparatorを決定する際に役立ちます。

1)コードの可用性

2)単一のソート基準と複数のソート基準

3)Arays.sort()およびCollection.sort()

4)SortedMapおよびSortedSetのキーとして

5)クラス数の増加と柔軟性

6)クラス間比較

7)自然秩序

詳細な記事については、 比較可能なものを使用する場合と比較器を使用する場合 を参照してください。

4
a Learner

自然な順序の並べ替えが必要な場合-カスタムの並べ替えが必要な場合はUser Comparable-Use Comparator

例:

Class Employee{
private int id;
private String name;
private String department;
}

自然順序ソートは一意であり、カスタムオーダーのソートは名前と部門であるため、IDに基づきます。

借り換え:
クラスをComparableおよび/またはComparatorにする必要がある場合http://javarevisited.blogspot.com/2011/06/comparator-and-comparable-in-Java .html

3
Rajiv

同様の質問がここにありました: クラスが比較可能および/または比較器である必要がありますか?

私は次のように言います:自然な順序のようなもののためにComparableを実装します内部IDに基づいて

より複雑な比較アルゴリズムがある場合は、コンパレータを実装します。複数のフィールドなど。

3
ZeissS

比較可能:
同種の要素とデフォルトの自然な並べ替え順序のみを保存する場合は、comparableインターフェイスを実装するクラスを選択できます。

コンパレータ:
同種および異種の要素を保存し、デフォルトのカスタマイズされた並べ替え順序で並べ替える場合は、comparatorインターフェイスを使用できます。

2
G swamy reddy

私のニーズは日付に基づいてソートされました。

そのため、Comparableを使用しましたが、簡単に機能しました。

public int compareTo(GoogleCalendarBean o) {
    // TODO Auto-generated method stub
    return eventdate.compareTo(o.getEventdate());
}

Comparableの制限の1つは、リスト以外のコレクションには使用できないことです。

0
spring pro

比較可能は、数値が昇順で、文字列がアルファベット順である場合に提供されるデフォルトの自然なソート順です。例えば:

Treeset t=new Treeset();
t.add(2);
t.add(1);
System.out.println(t);//[1,2]

Comparatorは、たとえば次のような比較メソッドをオーバーライドすることにより、カスタムmyComparatorクラスに実装されたカスタムソート順です。

Treeset t=new Treeset(new myComparator());
t.add(55);
t.add(56);
class myComparator implements Comparator{
public int compare(Object o1,Object o2){
//Descending Logic
}
}
System.out.println(t);//[56,55]
0
Ajay Takur

クラスを所有している場合は、Comparableを使用することをお勧めします。通常、Comparatorは、クラスを所有していないが使用する必要がある場合に使用されますTreeSetまたはTreeMap。これは、ComparatorをTreeSetまたはTreeMapのコンストラクターのパラメーターとして渡すことができるためです。 ComparatorとComparableの使用方法は http://preciselyconcise.com/Java/collections/g_comparator.php で確認できます。

0
Sai Sunder

インタビューの1つで、nlogn時間よりも明確な範囲の数値のソートを依頼されました。 (カウントソートを使用しない)

Comparableインターフェイスをオブジェクトに実装すると、暗黙的な並べ替えアルゴリズムでオーバーライドされたcompareToメソッドを使用して要素を並べ替えることができます。これは線形時間になります。

0
Mr. Wonderful