เมื่อใดควรใช้ตัวเปรียบเทียบและตัวเปรียบเทียบ


109

ฉันมีรายการวัตถุที่ต้องจัดเรียงบนสนามพูดว่า Score โดยไม่ต้องคิดมากฉันเขียนคลาสใหม่ที่ใช้ตัวเปรียบเทียบนั่นก็ทำงานและมันได้ผล

เมื่อมองย้อนกลับไปที่สิ่งนี้ฉันสงสัยว่าฉันควรให้คลาสของฉันใช้งาน Comparable แทนการสร้างคลาสใหม่ที่ใช้ Comparator หรือไม่ คะแนนเป็นช่องเดียวที่จะเรียงลำดับวัตถุ

  1. สิ่งที่ฉันได้ทำนั้นเป็นที่ยอมรับในเชิงปฏิบัติหรือไม่?

  2. เป็นแนวทางที่ถูกต้อง "อันดับแรกให้คลาสใช้งานเทียบเคียงได้ (สำหรับการจัดลำดับตามธรรมชาติ) และหากจำเป็นต้องมีการเปรียบเทียบฟิลด์ทางเลือกให้สร้างคลาสใหม่ที่ใช้ตัวเปรียบเทียบ"

  3. ถ้า (2) ข้างต้นเป็นจริงหมายความว่าควรใช้ Comparator หลังจากที่พวกเขามีคลาสใช้งาน Comparable หรือไม่? (สมมติว่าฉันเป็นเจ้าของคลาสเดิม)

คำตอบ:


80

ฉันจะบอกว่าออบเจ็กต์ควรใช้การเทียบเคียงถ้านั่นเป็นวิธีธรรมชาติที่ชัดเจนในการจัดเรียงคลาสและใคร ๆ ก็ต้องเรียงคลาสโดยทั่วไปก็อยากทำแบบนั้น

อย่างไรก็ตามหากการเรียงลำดับเป็นการใช้คลาสที่ผิดปกติหรือการเรียงลำดับเหมาะสมกับกรณีการใช้งานที่เฉพาะเจาะจงเท่านั้นตัวเปรียบเทียบก็เป็นตัวเลือกที่ดีกว่า

พูดอีกอย่างคือตั้งชื่อคลาสชัดเจนไหมว่าการเทียบเคียงจะเรียงลำดับอย่างไรหรือคุณต้องหันไปอ่าน javadoc? หากเป็นอย่างหลังอัตราต่อรองคือทุกกรณีการใช้งานการเรียงลำดับในอนาคตจะต้องมีตัวเปรียบเทียบซึ่งในจุดนั้นการใช้งานการเทียบเคียงอาจทำให้ผู้ใช้ชั้นเรียนช้าลงไม่เร่งความเร็ว


ช่วยยกตัวอย่างด่วนได้ไหม
rgamber

นี่อาจเป็นตัวอย่างที่ดี: gist.github.com/yclian/2627608มีคลาส Version ที่ใช้ ComparableVersion เวอร์ชัน - จัดเตรียมวิธีการจากโรงงาน ComparableVersion ที่ควรจะเป็นอ็อบเจ็กต์ (โดยไม่มีวิธีการคงที่) - ให้เวอร์ชันที่สามารถเปรียบเทียบกับเวอร์ชันอื่นได้ ความรับผิดชอบจะแยกจากกัน
ses

2
คุณสามารถอ้างอิงjava-journal.blogspot.in/2011/01/…
ผู้เรียน

ผู้สัมภาษณ์ถามว่าทำไมต้องใช้ Comparator ในเมื่อสามารถทำได้กับ Comparable และฉันก็โง่ :(
Aadam

ลิงค์ @aLearner ตาย
G.Brown

127

ใช้Comparableหากคุณต้องการกำหนดพฤติกรรมการสั่งซื้อเริ่มต้น (ตามธรรมชาติ) ของวัตถุที่เป็นปัญหาแนวทางปฏิบัติทั่วไปคือการใช้ตัวระบุ (ฐานข้อมูล) ทางเทคนิคหรือตามธรรมชาติของวัตถุสำหรับสิ่งนี้

ใช้Comparatorหากคุณต้องการกำหนดลักษณะการสั่งซื้อที่ควบคุมได้ภายนอกซึ่งสามารถแทนที่พฤติกรรมการสั่งซื้อเริ่มต้นได้


3
นั่นเป็นคำอธิบายทางเทคนิคและถูกต้องตามที่มา แต่ก็ไม่ได้พูดอะไรเกี่ยวกับแนวทางปฏิบัติที่ดีที่สุด
ภายนอก

40
มันบอกว่าเมื่อไหร่ควรใช้ - ถ้านั่นไม่ใช่แนวทางปฏิบัติที่ดีที่สุดมันคืออะไร?
Bozho

1
"การใช้งานComparableหมายความว่าฉันกำลังกำหนดลำดับตามธรรมชาติหรือไม่" สิ่งนี้ทำให้ฉันได้รับคำตอบที่ฉันกำลังมองหา ขอบคุณ :)
สมจิตร

61

ใช้Comparable:

  • ถ้าวัตถุอยู่ในการควบคุมของคุณ
  • ถ้าพฤติกรรมการเปรียบเทียบเป็นพฤติกรรมหลักในการเปรียบเทียบ

ใช้Comparator:

  • หากวัตถุอยู่นอกการควบคุมของคุณและคุณไม่สามารถนำไปใช้งานComparableได้
  • เมื่อคุณต้องการเปรียบเทียบพฤติกรรมที่แตกต่างจากพฤติกรรมเริ่มต้น (ซึ่งระบุโดยComparable) พฤติกรรม

22

เทียบเคียง -java.lang.Comparable: int compareTo(Object o1)

วัตถุที่เทียบเคียงสามารถเปรียบเทียบตัวเองกับวัตถุอื่นได้ คลาสนั้นต้องใช้อินเทอร์เฟซ java.lang.Comparable เพื่อที่จะสามารถเปรียบเทียบอินสแตนซ์ได้

  • สามารถเปรียบเทียบวัตถุปัจจุบันกับวัตถุที่ให้มา
  • ด้วยการใช้สิ่งนี้เราสามารถนำไปใช้only one sort sequenceตามคุณสมบัติของอินสแตนซ์ EX:Person.id
  • คลาสที่กำหนดไว้ล่วงหน้าบางคลาสเช่นสตริง, คลาส Wrapper, วันที่, ปฏิทินได้ใช้อินเทอร์เฟซที่เปรียบเทียบได้

เครื่องเปรียบเทียบ -java.util.Comparator: int compare(Object o1, Object o2)

วัตถุเปรียบเทียบสามารถเปรียบเทียบวัตถุสองชิ้นที่แตกต่างกันได้ คลาสไม่ได้เปรียบเทียบอินสแตนซ์ แต่เป็นอินสแตนซ์ของคลาสอื่น คลาสตัวเปรียบเทียบนี้ต้องใช้อินเทอร์เฟซ java.util.Comparator

  • สามารถเปรียบเทียบออบเจ็กต์ประเภทเดียวกันสองชนิด
  • ด้วยการใช้สิ่งนี้เราสามารถใช้many sort sequenceและตั้งชื่อแต่ละรายการตามคุณสมบัติของอินสแตนซ์ EX:Person.id, Person.name, Person.age
  • เราสามารถใช้อินเทอร์เฟซตัวเปรียบเทียบกับคลาสที่กำหนดไว้ล่วงหน้าสำหรับการเรียงลำดับแบบกำหนดเอง

ตัวอย่าง:

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: ตัวเปรียบเทียบอ้างถึงโพสต์ของฉัน


10

ควรใช้การเปรียบเทียบเมื่อคุณเปรียบเทียบอินสแตนซ์ของคลาสเดียวกัน

ตัวเปรียบเทียบสามารถใช้เพื่อเปรียบเทียบอินสแตนซ์ของคลาสต่างๆ

การเปรียบเทียบจะถูกนำไปใช้โดยคลาสซึ่งจำเป็นต้องกำหนดลำดับตามธรรมชาติสำหรับวัตถุ เช่นเดียวกับสตริงที่ใช้เทียบเคียงได้

ในกรณีที่ต้องการลำดับการจัดเรียงที่แตกต่างกันเขาสามารถใช้ตัวเปรียบเทียบและกำหนดวิธีการเปรียบเทียบอินสแตนซ์สองอินสแตนซ์ของตัวเองได้


10

หากการเรียงลำดับของวัตถุต้องเป็นไปตามลำดับธรรมชาติให้ใช้การเปรียบเทียบในขณะที่ถ้าการเรียงลำดับของคุณจำเป็นต้องทำกับแอตทริบิวต์ของวัตถุที่แตกต่างกันให้ใช้ตัวเปรียบเทียบใน Java

ความแตกต่างหลักระหว่างเปรียบเทียบและเปรียบเทียบ:

+------------------------------------------------------------------------------------+
¦               Comparable                ¦                Comparator                ¦
¦-----------------------------------------+------------------------------------------¦
¦ java.lang.Comparable                    ¦ java.util.Comparator                     ¦
¦-----------------------------------------+------------------------------------------¦
¦ int objOne.compareTo(objTwo)            ¦ int compare(objOne, objTwo)              ¦
¦-----------------------------------------+------------------------------------------¦
¦ Negative, if objOne < objTwo            ¦ Same as Comparable                       ¦
¦ Zero,  if objOne == objTwo              ¦                                          ¦
¦ Positive,  if objOne > objTwo           ¦                                          ¦
¦-----------------------------------------+------------------------------------------¦
¦ You must modify the class whose         ¦ You build a class separate from to sort. ¦
¦ instances you want to sort.             ¦ the class whose instances you want       ¦
¦-----------------------------------------+------------------------------------------¦
¦ Only one sort sequence 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, Calendar ¦ instances of third-party classes.        ¦
+------------------------------------------------------------------------------------+

9

ตัวเปรียบเทียบทำทุกอย่างที่เทียบเคียงได้และอื่น ๆ

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

    ฯลฯ ...

ตอนนี้คุณสามารถใช้วิธีการเรียงลำดับเหล่านี้ได้ทุกที่และรับโค้ดซ้ำ สิ่งนี้ทำให้ฉันมีทุกสิ่งที่เทียบเคียงได้บวกมากขึ้น ... ดังนั้นฉันจึงไม่เห็นเหตุผลที่จะใช้การเทียบเคียงเลย


8

ฉันจะบอกว่า:

  • หากการเปรียบเทียบนั้นใช้งานง่ายดังนั้นโดยทั้งหมดใช้การเปรียบเทียบ
  • หากไม่ชัดเจนว่าการเปรียบเทียบของคุณใช้งานง่ายให้ใช้ตัวเปรียบเทียบเนื่องจากมีความชัดเจนมากขึ้นและจึงชัดเจนมากขึ้นสำหรับวิญญาณที่น่าสงสารที่ต้องรักษารหัส
  • หากมีการเปรียบเทียบที่ใช้งานง่ายมากกว่าหนึ่งรายการที่เป็นไปได้ฉันต้องการตัวเปรียบเทียบซึ่งอาจสร้างโดยวิธีการโรงงานในคลาสเพื่อเปรียบเทียบ
  • หากการเปรียบเทียบเป็นจุดประสงค์พิเศษให้ใช้ตัวเปรียบเทียบ

6

ประเด็นต่อไปนี้ช่วยคุณในการตัดสินใจว่าควรใช้การเทียบเคียงในสถานการณ์ใดและตัวเปรียบเทียบใด:

1) รหัส Availabilty

2) เกณฑ์การเรียงลำดับเดียวกับหลายรายการ

3) Arays.sort () และ Collection.sort ()

4) เป็นคีย์ใน SortedMap และ SortedSet

5) จำนวนชั้นเรียนมากขึ้นเมื่อเทียบกับความยืดหยุ่น

6) การเปรียบเทียบระหว่างคลาส

7) การสั่งซื้อตามธรรมชาติ

สำหรับบทความรายละเอียดเพิ่มเติมคุณสามารถอ้างถึงเมื่อใดควรใช้การเทียบเคียงและเมื่อใดควรใช้ตัวเปรียบเทียบ


ฉันสงสัยว่าทำไมไม่มีใครโหวตคำตอบนี้ มันเป็นสิ่งที่ดีจริงๆ +1
Diganta

4
  • หากในขณะที่เขียนชั้นเรียนคุณมีกรณีการใช้งานเพียงกรณีเดียวให้ใช้การเทียบเคียง
  • เฉพาะเมื่อคุณมีกลยุทธ์ในการจัดเรียงมากกว่าหนึ่งแบบให้ใช้ตัวเปรียบเทียบ

4

หากคุณต้องการการเรียงลำดับตามธรรมชาติ - ผู้ใช้เปรียบเทียบได้หากคุณต้องการการเรียงลำดับแบบกำหนดเอง - ใช้ตัวเปรียบเทียบ

ตัวอย่าง:

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

การเรียงลำดับตามธรรมชาติจะขึ้นอยู่กับ id เนื่องจากจะไม่ซ้ำกันและการเรียงลำดับที่กำหนดเอง g จะเป็นชื่อและแผนก

การอ้างอิง:
เมื่อใดควรเทียบเคียงชั้นเรียนและ / หรือตัวเปรียบเทียบ http://javarevisited.blogspot.com/2011/06/comparator-and-comparable-in-java.html


3

มีคำถามคล้าย ๆ กันที่นี่: เมื่อใดควรเทียบชั้นเรียนและ / หรือตัวเปรียบเทียบ

ฉันจะพูดต่อไปนี้: Implement Comparable สำหรับบางอย่างเช่นการสั่งซื้อตามธรรมชาติเช่นอิงตาม ID ภายใน

ใช้ตัวเปรียบเทียบหากคุณมีอัลกอริธึมการเปรียบเทียบที่ซับซ้อนมากขึ้นเช่นหลายช่องและอื่น ๆ


1
Comparableการสั่งซื้อในช่องหลายคนสามารถเป็นดีทำด้วย
BalusC

สำหรับความแตกต่างระหว่างตัวเปรียบเทียบและตัวเปรียบเทียบคุณสามารถอ้างอิงjava-journal.blogspot.in/2010/12/…
ผู้เรียน

2

เปรียบเทียบได้:
เมื่อใดก็ตามที่เราต้องการจัดเก็บเฉพาะองค์ประกอบที่เป็นเนื้อเดียวกันและต้องมีลำดับการเรียงลำดับตามธรรมชาติเริ่มต้นเราสามารถไปที่comparableอินเทอร์เฟซการใช้งานคลาส ได้

ตัวเปรียบเทียบ:
เมื่อใดก็ตามที่เราต้องการจัดเก็บองค์ประกอบที่เป็นเนื้อเดียวกันและต่างกันและเราต้องการจัดเรียงตามลำดับการเรียงลำดับที่กำหนดเองเริ่มต้นเราสามารถไปที่comparatorส่วนต่อประสานได้


0

ความต้องการของฉันเรียงตามวันที่

ดังนั้นฉันจึงใช้การเปรียบเทียบและมันใช้งานได้ง่ายสำหรับฉัน

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

ข้อ จำกัด อย่างหนึ่งของการเปรียบเทียบคือไม่สามารถใช้กับคอลเล็กชันอื่นที่ไม่ใช่รายการได้


0

หากคุณเป็นเจ้าของระดับดีขึ้นไปกับเทียบเคียง โดยทั่วไปตัวเปรียบเทียบจะใช้หากคุณไม่ได้เป็นเจ้าของคลาส แต่คุณต้องใช้TreeSetหรือTreeMapเนื่องจากตัวเปรียบเทียบสามารถส่งผ่านเป็นพารามิเตอร์ใน conctructor ของ TreeSet หรือ TreeMap ได้ คุณสามารถดูวิธีใช้ตัวเปรียบเทียบและเปรียบเทียบได้ในhttp://precilizedconcise.com/java/collections/g_comparator.php


0

ฉันถูกถามให้เรียงลำดับช่วงของตัวเลขที่แน่นอนดีกว่าเวลา nlogn ในการสัมภาษณ์ครั้งหนึ่ง (ไม่ใช้การเรียงลำดับการนับ)

การใช้อินเทอร์เฟซที่เปรียบเทียบได้บนวัตถุช่วยให้การเรียงลำดับโดยนัยสามารถใช้เมธอด CompareTo ที่ถูกแทนที่เพื่อจัดเรียงองค์ประกอบและนั่นจะเป็นเวลาเชิงเส้น


0

การเปรียบเทียบคือลำดับการเรียงลำดับตามธรรมชาติเริ่มต้นที่มีให้สำหรับค่าตัวเลขคือจากน้อยไปหามากและสำหรับสตริงจะเรียงตามตัวอักษร เช่น:

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

ตัวเปรียบเทียบคือลำดับการเรียงลำดับแบบกำหนดเองที่ใช้ในคลาส 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]

-1

วิธีการที่ง่ายมากคือการสมมติว่าคลาสเอนทิตีที่เป็นปัญหาถูกแสดงในฐานข้อมูลจากนั้นในตารางฐานข้อมูลคุณต้องการดัชนีที่ประกอบด้วยฟิลด์ของคลาสเอนทิตีหรือไม่? ถ้าคำตอบคือใช่ให้ใช้การเทียบเคียงและใช้ฟิลด์ดัชนีสำหรับลำดับการเรียงลำดับตามธรรมชาติ ในกรณีอื่น ๆ ให้ใช้ตัวเปรียบเทียบ


-2

คำอธิบายประกอบของฉัน lib สำหรับการใช้งานComparableและComparator:

public class Person implements Comparable<Person> {         
    private String firstName;  
    private String lastName;         
    private int age;         
    private char gentle;         

    @Override         
    @CompaProperties({ @CompaProperty(property = "lastName"),              
        @CompaProperty(property = "age",  order = Order.DSC) })           
    public int compareTo(Person person) {                 
        return Compamatic.doComparasion(this, person);         
    }  
}

คลิกลิงค์เพื่อดูตัวอย่างเพิ่มเติม http://code.google.com/p/compamatic/wiki/CompamaticByExamples

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.