วิธีการเรียงลำดับรายการของวัตถุตามคุณสมบัติบางอย่าง


145

ฉันมีชั้นเรียนที่เรียบง่าย

public class ActiveAlarm {
    public long timeStarted;
    public long timeEnded;
    private String name = "";
    private String description = "";
    private String event;
    private boolean live = false;
}

และList<ActiveAlarm>ต่อต้าน วิธีการเรียงลำดับจากน้อยไปมากเรียงลำดับตามtimeStartedแล้วตามด้วยtimeEnded? ใครช่วยได้บ้าง ฉันรู้ใน C ++ พร้อมอัลกอริทึมทั่วไปและตัวดำเนินการโอเวอร์โหลด <แต่ฉันใหม่สำหรับ Java


คำตอบโดย @Yishai ในโพสต์นี้แสดงให้เห็นถึงการใช้ enum อย่างหรูหราสำหรับการเรียงลำดับแบบกำหนดเองและการเรียงลำดับที่จัดกลุ่ม
gunalmel

คำตอบ:


140

ทำการActiveAlarmใช้งานComparable<ActiveAlarm>หรือนำไปใช้Comparator<ActiveAlarm>ในคลาสที่แยกต่างหาก จากนั้นโทร:

Collections.sort(list);

หรือ

Collections.sort(list, comparator);

โดยทั่วไปแล้วมันเป็นความคิดที่ดีที่จะใช้Comparable<T>ถ้ามีเพียงหนึ่งเดียว "ธรรมชาติ" ลำดับการจัดเรียง ... มิฉะนั้น (ถ้าคุณเกิดขึ้นเพื่อต้องการเรียงลำดับในลำดับโดยเฉพาะ แต่อาจจะเท่าเทียมกันได้อย่างง่ายดายต้องการที่แตกต่างกันอย่างใดอย่างหนึ่ง) Comparator<T>มันจะดีกว่าที่จะใช้ สถานการณ์แบบนี้อาจไปในทางใดทางหนึ่งโดยสุจริต ... แต่ฉันอาจจะติดกับComparator<T>ตัวเลือกที่ยืดหยุ่นกว่า

แก้ไข: การใช้งานตัวอย่าง:

public class AlarmByTimesComparer implements Comparator<ActiveAlarm> {
  @Override
  public int compare(ActiveAlarm x, ActiveAlarm y) {
    // TODO: Handle null x or y values
    int startComparison = compare(x.timeStarted, y.timeStarted);
    return startComparison != 0 ? startComparison
                                : compare(x.timeEnded, y.timeEnded);
  }

  // I don't know why this isn't in Long...
  private static int compare(long a, long b) {
    return a < b ? -1
         : a > b ? 1
         : 0;
  }
}

1
ฟังก์ชั่นการเปรียบเทียบ () นั้นไม่ได้มีความเป็นไปได้ที่ยาวนานเพราะการนำไปใช้นั้นมีความสำคัญมากกว่านั้น: ส่งคืน a - b;
papercrane

5
@ papercrane: ไม่, ที่ล้มเหลวด้วยเหตุผลล้น a = Long.MIN_VALUE, b = 1พิจารณา
Jon Skeet

3
ในฐานะของ API 19 (KitKat) ปัจจุบันมี.compare
Martin Marconcini

123

การใช้ Comparator

ตัวอย่างเช่น:

class Score {

    private String name;
    private List<Integer> scores;
    // +accessor methods
}

    Collections.sort(scores, new Comparator<Score>() {

        public int compare(Score o1, Score o2) {
            // compare two instance of `Score` and return `int` as result.
            return o2.getScores().get(0).compareTo(o1.getScores().get(0));
        }
    });

ด้วย Java 8 เป็นต้นไปคุณสามารถใช้แลมบ์ดานิพจน์เพื่อแทนอินสแตนซ์ของตัวเปรียบเทียบ

Collections.sort(scores, (s1, s2) -> { /* compute and return int */ });

1
อะไรcompareTo()ทำอย่างไร มันมาจากไหน? ฉันต้องกำหนดมันที่ไหน
Asqiir

1
@Asqiir getScores()เป็น getter สำหรับซึ่งเป็นscores List<Integer>เมื่อคุณgetScores().get(0)ได้รับIntegerวัตถุ IntegerมีcompareTo(anotherInteger)วิธีการนำไปใช้แล้วคุณไม่จำเป็นต้องกำหนด
walen

อะไรได้รับ (0)
Ali Khaki

1
ขอบคุณทำงานเหมือนมีเสน่ห์ (ฉันใช้โดยไม่มีส่วน. get (0)) ฉันจะกลับคำสั่งซื้อได้อย่างไร

53

คำตอบ JAVA 8 ขึ้นไป (การใช้แลมบ์ดานิพจน์)

ใน Java 8 นิพจน์แลมบ์ดาถูกนำมาใช้เพื่อทำให้สิ่งนี้ง่ายยิ่งขึ้น! แทนที่จะสร้างวัตถุ Comparator () พร้อมนั่งร้านทั้งหมดคุณสามารถทำให้มันง่ายขึ้นดังนี้: (ใช้วัตถุเป็นตัวอย่าง)

Collections.sort(list, (ActiveAlarm a1, ActiveAlarm a2) -> a1.timeStarted-a2.timeStarted);

หรือสั้นกว่า:

Collections.sort(list, Comparator.comparingInt(ActiveAlarm ::getterMethod));

คำสั่งเดียวนั้นเทียบเท่ากับสิ่งต่อไปนี้:

Collections.sort(list, new Comparator<ActiveAlarm>() {
    @Override
    public int compare(ActiveAlarm a1, ActiveAlarm a2) {
        return a1.timeStarted - a2.timeStarted;
    }
});

ลองนึกถึงการแสดงออกของแลมบ์ดาว่าให้คุณใส่เฉพาะในส่วนที่เกี่ยวข้องของรหัส: ลายเซ็นวิธีการและสิ่งที่ได้รับคืน

อีกคำถามหนึ่งของคุณคือวิธีเปรียบเทียบกับหลาย ๆ ฟิลด์ ในการทำเช่นนั้นกับนิพจน์แลมบ์ดาคุณสามารถใช้.thenComparing()ฟังก์ชันเพื่อรวมการเปรียบเทียบสองรายการเข้าด้วยกันเป็นหนึ่งเดียวได้อย่างมีประสิทธิภาพ:

Collections.sort(list, (ActiveAlarm a1, ActiveAlarm a2) -> a1.timeStarted-a2.timeStarted             
       .thenComparing ((ActiveAlarm a1, ActiveAlarm a2) -> a1.timeEnded-a2.timeEnded)
);

รหัสด้านบนจะเรียงลำดับรายการเป็นลำดับแรกจากtimeStartedนั้นตามด้วยtimeEnded(สำหรับระเบียนที่มีเหมือนกันtimeStarted)

หมายเหตุสุดท้ายหนึ่ง: มันเป็นการง่ายที่จะเปรียบเทียบแบบดั้งเดิม 'long' หรือ 'int' คุณสามารถลบอันใดอันหนึ่งจากอีกอันหนึ่งได้ หากคุณกำลังเปรียบเทียบวัตถุ ('ยาว' หรือ 'สตริง') ฉันขอแนะนำให้คุณใช้การเปรียบเทียบในตัว ตัวอย่าง:

Collections.sort(list, (ActiveAlarm a1, ActiveAlarm a2) -> a1.name.compareTo(a2.name) );

แก้ไข: ขอบคุณ Lukas Eder สำหรับการชี้ให้ฉัน.thenComparing()ทำงาน


4
คุณอาจจะพอใจกับ Java 8 API ใหม่Comparator.comparing().thenComparing()...
Lukas Eder

1
ระวังด้วยความแตกต่างที่กลับมา ในกรณีที่มีการล้นคุณสามารถได้รับผลที่ผิด
krzychu

2
นี่เป็นวิธีการเรียงลำดับที่ง่ายกว่า IMHO สมมติว่าคุณไม่มีระเบียบตามธรรมชาติที่ชัดเจน คุณไม่จำเป็นต้องโทรCollectionsอีกต่อไปคุณสามารถโทรเข้าสู่รายการได้โดยตรง ตัวอย่างเช่น:myList.sort(Comparator.comparing(Address::getZipCode).thenComparing(Compartor.comparing(Address::getStreetName));
CeePlusPlus

20

เราสามารถจัดเรียงรายการได้สองวิธี:

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

  Collections.sort(arrayList, new Comparator<ActiveAlarm>() {
        public int compare(ActiveAlarm o1, ActiveAlarm o2) {
            //Sorts by 'TimeStarted' property
            return o1.getTimeStarted()<o2.getTimeStarted()?-1:o1.getTimeStarted()>o2.getTimeStarted()?1:doSecodaryOrderSort(o1,o2);
        }

        //If 'TimeStarted' property is equal sorts by 'TimeEnded' property
        public int doSecodaryOrderSort(ActiveAlarm o1,ActiveAlarm o2) {
            return o1.getTimeEnded()<o2.getTimeEnded()?-1:o1.getTimeEnded()>o2.getTimeEnded()?1:0;
        }
    });

เราสามารถตรวจสอบคุณสมบัติเป็นโมฆะหากเราสามารถใช้ 'ยาว' แทน 'ยาว'

2. การใช้ Comparable (การเรียงตามลำดับแบบธรรมชาติ) : หากอัลกอริธึมการเรียงลำดับติดกับคุณสมบัติหนึ่งเสมอ: เขียนคลาสที่ใช้เมธอด 'Comparable' และ Override 'comparTo' ตามที่กำหนดไว้ด้านล่าง

class ActiveAlarm implements Comparable<ActiveAlarm>{

public long timeStarted;
public long timeEnded;
private String name = "";
private String description = "";
private String event;
private boolean live = false;

public ActiveAlarm(long timeStarted,long timeEnded) {
    this.timeStarted=timeStarted;
    this.timeEnded=timeEnded;
}

public long getTimeStarted() {
    return timeStarted;
}

public long getTimeEnded() {
    return timeEnded;
}

public int compareTo(ActiveAlarm o) {
    return timeStarted<o.getTimeStarted()?-1:timeStarted>o.getTimeStarted()?1:doSecodaryOrderSort(o);
}

public int doSecodaryOrderSort(ActiveAlarm o) {
    return timeEnded<o.getTimeEnded()?-1:timeEnded>o.getTimeEnded()?1:0;
}

}

วิธีการเรียงลำดับการโทรเพื่อเรียงลำดับตามการสั่งซื้อแบบธรรมชาติ

Collections.sort(list);

7

ใน java8 + สามารถเขียนเป็นบรรทัดเดียวดังนี้:

collectionObjec.sort(comparator_lamda) หรือ comparator.comparing(CollectionType::getterOfProperty)

รหัส:

ListOfActiveAlarmObj.sort((a,b->a.getTimeStarted().compareTo(b.getTimeStarted())))
 

หรือ

ListOfActiveAlarmObj.sort(Comparator.comparing(ActiveAlarm::getTimeStarted))

5
public class ActiveAlarm implements Comparable<ActiveAlarm> {
    public long timeStarted;
    public long timeEnded;
    private String name = "";
    private String description = "";
    private String event;
    private boolean live = false;

    public int compareTo(ActiveAlarm a) {
        if ( this.timeStarted > a.timeStarted )
            return 1;
        else if ( this.timeStarted < a.timeStarted )
            return -1;
        else {
             if ( this.timeEnded > a.timeEnded )
                 return 1;
             else
                 return -1;
        }
 }

นั่นควรให้ความคิดคร่าวๆกับคุณ เมื่อเสร็จแล้วคุณสามารถโทรCollections.sort()ในรายการ


4

ตั้งแต่ Java8 สิ่งนี้สามารถทำได้แม้จะสะอาดกว่าโดยใช้การรวมกันของComparatorและLambda expressions

ตัวอย่างเช่น:

class Student{

    private String name;
    private List<Score> scores;

    // +accessor methods
}

class Score {

    private int grade;
    // +accessor methods
}

    Collections.sort(student.getScores(), Comparator.comparing(Score::getGrade);



1

ในจาวาคุณต้องใช้Collections.sortวิธีการคงที่ นี่คือตัวอย่างสำหรับรายการของวัตถุ CompanyRole เรียงลำดับโดยเริ่มต้นแล้วตามด้วยสิ้นสุด คุณสามารถปรับให้เข้ากับวัตถุของคุณได้อย่างง่ายดาย

private static void order(List<TextComponent> roles) {

    Collections.sort(roles, new Comparator() {
        @Override
        public int compare(Object o1, Object o2) {
            int x1 = ((CompanyRole) o1).getBegin();
            int x2 = ((CompanyRole) o2).getBegin();

            if (x1 != x2) {
                return x1 - x2;
            } else {
                int y1 = ((CompanyRole) o1).getEnd();
                int y2 = ((CompanyRole) o2).getEnd();
                return y2 - y1;
            }
        }
    });
}

0

คุณสามารถเรียก Collections.sort () และส่งผ่าน Comparator ซึ่งคุณต้องเขียนเพื่อเปรียบเทียบคุณสมบัติที่แตกต่างกันของวัตถุ


0

ดังกล่าวคุณสามารถจัดเรียงตาม:

  • ทำให้วัตถุของคุณใช้ Comparable
  • หรือผ่านComparatorไปCollections.sort

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

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