0Pricing
Java Academy · บทเรียน

การเรียงลำดับหลายคีย์ด้วย thenComparing

เชื่อม comparator ด้วย thenComparing เพื่อเรียงลำดับตามหลายฟิลด์ โดยเรียงตามลำดับความสำคัญ

การเรียงลำดับหลายคีย์ด้วย thenComparing เป็นบทเรียน Java Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Java Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน

การจัดเรียงด้วยหลายคีย์

thenComparing() เชื่อม Comparator เพื่อจัดเรียงตามหลายฟิลด์ โดยจัดเรียงฟิลด์หลักก่อน หากเท่ากันจึงจัดเรียงฟิลด์รอง และดำเนินการเช่นนี้ต่อไป

thenComparing พื้นฐาน

ใช้ thenComparing() เพื่อแยกกรณีที่เท่ากันหลังจากใช้ Comparator หลัก

import java.util.*;

record Student(String name, int grade, double gpa) {}

List<Student> students = List.of(
    new Student("Alice",   10, 3.9),
    new Student("Bob",     11, 3.7),
    new Student("Charlie", 10, 3.8),
    new Student("Diana",   11, 3.7)
);

Comparator<Student> sort = Comparator.comparingInt(Student::grade)
    .thenComparingDouble(Student::gpa).reversed()
    .thenComparing(Student::name);

students.stream().sorted(sort).forEach(System.out::println);

การจัดเรียงสามระดับ

เชื่อมระดับ thenComparing ได้มากเท่าที่ต้องการ

record Employee(String dept, String team, String name, double salary) {}

List<Employee> employees = List.of(
    new Employee("Eng", "Backend", "Alice",   95000),
    new Employee("Eng", "Backend", "Bob",     92000),
    new Employee("Eng", "Frontend","Charlie", 88000),
    new Employee("Mkt", "Growth",  "Diana",   75000)
);

Comparator<Employee> sort = Comparator
    .comparing(Employee::dept)
    .thenComparing(Employee::team)
    .thenComparing(Comparator.comparingDouble(Employee::salary).reversed());

employees.stream().sorted(sort)
    .forEach(e -> System.out.printf("%s > %s > %s: $%.0f%n",
        e.dept(), e.team(), e.name(), e.salary()));

thenComparing กับ Comparator

ใช้รูปแบบโอเวอร์โหลดที่รับ Comparator เมื่อจำเป็นต้องกลับลำดับหรือกำหนดลำดับแบบกำหนดเองสำหรับคีย์รอง

Comparator<Employee> sort = Comparator
    .comparing(Employee::dept)
    .thenComparing(Comparator.comparing(Employee::salary).reversed()); // highest paid first
    // equivalent: .thenComparingDouble(Employee::salary, Comparator.reverseOrder())

การจัดเรียงโดยมีฟิลด์ที่เป็น null

ใช้ thenComparing ร่วมกับ nullsLast/nullsFirst เพื่อจัดการฟิลด์ที่อาจไม่มีค่าได้อย่างเหมาะสม

record Product(String name, String category, Double rating) {}

Comparator<Product> sort = Comparator
    .comparing(Product::category, Comparator.nullsLast(Comparator.naturalOrder()))
    .thenComparing(Product::rating,  Comparator.nullsLast(Comparator.reverseOrder()))
    .thenComparing(Product::name);

การเลือกคีย์จัดเรียงแบบไดนามิก

เลือกคีย์จัดเรียงขณะโปรแกรมทำงานตามความต้องการของผู้ใช้

static Comparator<Product> sortBy(String key) {
    return switch (key) {
        case "price"    -> Comparator.comparingDouble(Product::price);
        case "name"     -> Comparator.comparing(Product::name);
        case "stock"    -> Comparator.comparingInt(Product::stock).reversed();
        default         -> Comparator.comparingDouble(Product::price);
    };
}

String userChoice = "stock";
products.stream().sorted(sortBy(userChoice)).forEach(System.out::println);

thenComparing กับฟังก์ชันดึงค่า

รูปแบบโอเวอร์โหลด thenComparing(Function<T,U>) จะดึงคีย์ที่เป็น Comparable สำหรับการจัดเรียงรอง โดยไม่ต้องใช้ Comparator อย่างชัดเจน

record Event(String type, int year, int month, int day) {}

Comparator<Event> chronological = Comparator
    .comparing(Event::type)
    .thenComparingInt(Event::year)
    .thenComparingInt(Event::month)
    .thenComparingInt(Event::day);

การจัดเรียงคอลเลกชันของเรคคอร์ด

เรคคอร์ดที่มีเมธอดเข้าถึงค่าทำงานร่วมกับการอ้างอิงเมธอดในสายการทำงานของ Comparator ได้อย่างราบรื่น

record Order(String customerId, String status, double total, java.time.LocalDate date) {}

List<Order> orders = loadOrders();

Comparator<Order> byCustomerThenDate = Comparator
    .comparing(Order::customerId)
    .thenComparing(Order::date, Comparator.reverseOrder()); // newest first per customer

orders.stream().sorted(byCustomerThenDate)
    .collect(Collectors.groupingBy(Order::customerId))
    .forEach((cust, ords) -> {
        System.out.println("Customer: " + cust);
        ords.forEach(o -> System.out.println("  " + o.date() + " $" + o.total()));
    });

การรับประกันการจัดเรียงแบบคงลำดับ

List.sort() และ Arrays.sort() ของ Java สำหรับวัตถุใช้การจัดเรียงแบบผสานที่คงลำดับ องค์ประกอบที่เปรียบเทียบแล้วเท่ากันจะคงลำดับสัมพัทธ์เดิมไว้

// Stable sort example:
// First sort by name, then by dept
// Equal dept elements preserve the name order from previous sort
List<Employee> sorted = employees.stream()
    .sorted(Comparator.comparing(Employee::name))     // 1st pass
    .sorted(Comparator.comparing(Employee::dept))     // 2nd pass (stable!)
    .collect(Collectors.toList());
// Within each dept, employees remain alphabetically sorted

Comparator.comparing กับ Comparator ของคีย์

รูปแบบสองอาร์กิวเมนต์ Comparator.comparing(keyExtractor, keyComparator) ทำให้คุณระบุทั้งคีย์และลำดับของคีย์นั้นได้

// Sort by name length, then alphabetically within same length
Comparator<String> c = Comparator
    .comparing(String::length, Integer::compare)
    .thenComparing(Comparator.naturalOrder());

List<String> words = new ArrayList<>(List.of("fig","apple","kiwi","banana","pea"));
words.sort(c);
System.out.println(words); // [fig, pea, kiwi, apple, banana]

ในโลกจริง: ผลลัพธ์การค้นหาเที่ยวบิน

การเรียงลำดับผลลัพธ์การค้นหาเที่ยวบินตามราคา ตามด้วยระยะเวลา และเวลาออกเดินทาง

record Flight(String airline, double price, int durationMin, java.time.LocalTime departs) {}

Comparator<Flight> bestFlight = Comparator
    .comparingDouble(Flight::price)
    .thenComparingInt(Flight::durationMin)
    .thenComparing(Flight::departs);

การรวบรวมผลลัพธ์ที่เรียงลำดับแล้ว

ผสานการเรียงลำดับหลายคีย์เข้ากับตัวรวบรวม เพื่อสร้างกลุ่มหรือแผนที่ที่เรียงลำดับแล้ว

Map<String, List<Employee>> byDept = employees.stream()
    .sorted(Comparator.comparing(Employee::dept)
        .thenComparing(Comparator.comparingDouble(Employee::salary).reversed()))
    .collect(Collectors.groupingBy(Employee::dept,
        LinkedHashMap::new,  // preserve insertion (sorted) order
        Collectors.toList()));

byDept.forEach((dept, emps) -> {
    System.out.println(dept + ":");
    emps.forEach(e -> System.out.println("  " + e.name() + " $" + e.salary()));
});

ตรวจสอบความเข้าใจอย่างรวดเร็ว

คุณต้องการเรียงลำดับพนักงานตามแผนกในลำดับตัวอักษรก่อน แล้วจึงเรียงตามเงินเดือนจากมากไปน้อย ลำดับการเรียกใดถูกต้อง

สรุป: การเรียงลำดับหลายคีย์ด้วย thenComparing

ประเด็นสำคัญ:

  • thenComparing() เพิ่มคีย์การเรียงลำดับรอง ซึ่งจะนำมาใช้เมื่อคีย์หลักมีค่าเท่ากัน
  • เชื่อม thenComparing ได้มากเท่าที่ต้องการ
  • ใช้ thenComparing(ตัวเปรียบเทียบ) ร่วมกับ reversed() เมื่อคีย์รองต้องเรียงจากมากไปน้อย
  • ใช้ร่วมกับ nullsFirst/nullsLast สำหรับฟิลด์ที่อาจไม่มีค่า
  • List.sort() ของ Java มีความเสถียร — องค์ประกอบที่เท่ากันจะคงลำดับเดิมไว้
  • การเลือกการเรียงลำดับแบบไดนามิก: ใช้ switch เพื่อคืนค่าตัวเปรียบเทียบที่ถูกต้องขณะทำงาน

คำถามที่พบบ่อย

บทเรียน “การเรียงลำดับหลายคีย์ด้วย thenComparing” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การเรียงลำดับหลายคีย์ด้วย thenComparing” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Java Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การเรียงลำดับหลายคีย์ด้วย thenComparing”

เชื่อม comparator ด้วย thenComparing เพื่อเรียงลำดับตามหลายฟิลด์ โดยเรียงตามลำดับความสำคัญ คุณปฏิบัติ Java Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Java Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Java Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน

บทเรียน “การเรียงลำดับหลายคีย์ด้วย thenComparing” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Java Academy นี้ได้ไหม

ได้ บทเรียน Java Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. อินเทอร์เฟซ Comparable
  2. Comparator และการเรียงลำดับด้วย Lambda
  3. การเรียงลำดับหลายคีย์ด้วย thenComparing
  4. การเรียงลำดับอาร์เรย์และคอลเลกชันในทางปฏิบัติ
← กลับไปที่ Java Academy