partitioningBy และ counting
แบ่งสตรีมออกเป็นสองกลุ่มด้วย partitioningBy และนับองค์ประกอบด้วย counting
partitioningBy และ counting เป็นบทเรียน Java Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Java Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน
พื้นฐานของ partitioningBy
Collectors.partitioningBy(predicate) แบ่งสตรีมออกเป็นสองกลุ่มพอดี ได้แก่ true และ false แล้วคืนค่าเป็น Map<Boolean, List<T>>
import java.util.*;
import java.util.stream.*;
List<Integer> nums = List.of(1,2,3,4,5,6,7,8,9,10);
Map<Boolean, List<Integer>> evenOdd =
nums.stream().collect(Collectors.partitioningBy(n -> n % 2 == 0));
System.out.println(evenOdd.get(true)); // [2, 4, 6, 8, 10]
System.out.println(evenOdd.get(false)); // [1, 3, 5, 7, 9]partitioningBy เทียบกับ filter
ต่างจาก filter ตรงที่ partitioningBy จะเก็บทั้งสองกลุ่มไว้พร้อมกัน จึงเหมาะเมื่อคุณต้องการข้อมูลทั้งสองส่วนของการแบ่งกลุ่ม
record Student(String name, int score) {}
List<Student> students = List.of(
new Student("Alice",90), new Student("Bob",55),
new Student("Carol",72), new Student("Dave",48)
);
Map<Boolean, List<Student>> result =
students.stream().collect(
Collectors.partitioningBy(s -> s.score() >= 60)
);
System.out.println("Passed: " + result.get(true).size());
System.out.println("Failed: " + result.get(false).size());การใช้ตัวรวบรวมปลายทางกับ partitioningBy
รวม partitioningBy กับตัวรวบรวมปลายทางได้เช่นเดียวกับ groupingBy:
Map<Boolean, Long> passFailCount =
students.stream().collect(
Collectors.partitioningBy(
s -> s.score() >= 60,
Collectors.counting()
)
);
System.out.println("Passed: " + passFailCount.get(true));
System.out.println("Failed: " + passFailCount.get(false));ตัวรวบรวม counting()
Collectors.counting() นับจำนวนองค์ประกอบในสตรีมหรือกลุ่มปลายทาง ซึ่งเทียบเท่าอย่างสะดวกกับ reducing(0L, e -> 1L, Long::sum)
long count = Stream.of("a","bb","ccc","dddd")
.collect(Collectors.counting());
System.out.println(count); // 4
// Same as:
long count2 = Stream.of("a","bb","ccc","dddd").count();
// Use counting() as a downstream; use .count() as a terminal opการใช้ counting() เป็นตัวรวบรวมปลายทาง
counting() มีประโยชน์อย่างยิ่งเมื่อใช้เป็นตัวรวบรวมปลายทางสำหรับ groupingBy/partitioningBy:
List<String> words = List.of("cat","dog","car","door","cup","dune");
Map<Character, Long> byFirstLetter =
words.stream().collect(
Collectors.groupingBy(w -> w.charAt(0), Collectors.counting())
);
byFirstLetter.forEach((c, n) -> System.out.println(c + ": " + n));
// c: 3, d: 3แบ่งกลุ่มเป็นชื่อ
ดึงชื่อจากแต่ละกลุ่มโดยใช้ mapping เป็นตัวรวบรวมปลายทาง:
Map<Boolean, List<String>> namesByPass =
students.stream().collect(
Collectors.partitioningBy(
s -> s.score() >= 60,
Collectors.mapping(Student::name, Collectors.toList())
)
);
System.out.println("Passed: " + namesByPass.get(true));
System.out.println("Failed: " + namesByPass.get(false));การใช้ counting ร่วมกับ summarizingInt
Collectors.summarizingInt() คำนวณจำนวน ผลรวม ค่าต่ำสุด ค่าสูงสุด และค่าเฉลี่ยได้ในการส่งผ่านครั้งเดียว:
IntSummaryStatistics stats =
students.stream().collect(
Collectors.summarizingInt(Student::score)
);
System.out.println("Count: " + stats.getCount());
System.out.println("Average: " + stats.getAverage());
System.out.println("Max: " + stats.getMax());
System.out.println("Min: " + stats.getMin());กรณีใช้งานจริง: การแบ่งกลุ่มการทดลอง A/B
แบ่งผู้ใช้เป็นกลุ่มควบคุมและกลุ่มที่ได้รับการทดลองสำหรับการทดสอบ A/B:
record User(String id, boolean isInTreatment) {}
List<User> users = List.of(
new User("u1",true), new User("u2",false),
new User("u3",true), new User("u4",false)
);
Map<Boolean, Long> split =
users.stream().collect(
Collectors.partitioningBy(User::isInTreatment, Collectors.counting())
);
System.out.println("Treatment: " + split.get(true)); // 2
System.out.println("Control: " + split.get(false)); // 2แมปความถี่ด้วย groupingBy + counting
นับจำนวนครั้งที่แต่ละองค์ประกอบปรากฏ เช่น แมปความถี่ของคำ:
List<String> words2 = List.of("apple","banana","apple","cherry","banana","apple");
Map<String, Long> freq =
words2.stream().collect(
Collectors.groupingBy(w -> w, Collectors.counting())
);
freq.entrySet().stream()
.sorted(Map.Entry.<String,Long>comparingByValue().reversed())
.forEach(e -> System.out.println(e.getKey()+": "+e.getValue()));partitioningBy คืนค่าคีย์ทั้งสองเสมอ
ต่างจาก groupingBy ตรงที่ partitioningBy จะคืนแมปที่มีทั้งคีย์ true และ false เสมอ แม้กลุ่มใดกลุ่มหนึ่งจะว่างเปล่าก็ตาม จึงหลีกเลี่ยง NullPointerExceptions เมื่อใช้ map.get(true)
List<Integer> allEven = List.of(2,4,6);
Map<Boolean, List<Integer>> m =
allEven.stream().collect(Collectors.partitioningBy(n -> n % 2 != 0));
System.out.println(m.get(true)); // [] (empty, not null)
System.out.println(m.get(false)); // [2, 4, 6]ประสิทธิภาพ: การส่งผ่านครั้งเดียว
ทั้ง partitioningBy และ counting ทำงานโดยส่งผ่านสตรีมเพียงครั้งเดียว หรือ O(n) และไม่จำเป็นต้องจัดเรียงข้อมูล จึงมีประสิทธิภาพมากกว่าการเรียก filter สองครั้งหรือจัดเรียงข้อมูลก่อนจัดกลุ่มอย่างมาก
ตรวจสอบความเข้าใจ
ชนิดข้อมูลที่คืนค่าจาก Collectors.partitioningBy(predicate) คืออะไร
สรุป: partitioningBy และ counting
ประเด็นสำคัญ:
- partitioningBy แบ่งข้อมูลออกเป็นสองกลุ่มพอดี ได้แก่ จริงและเท็จ
- มีคีย์ทั้งสองเสมอ จึงไม่มีความเสี่ยง NPE เหมือน groupingBy
- counting() ใช้นับองค์ประกอบ และใช้เป็นตัวรวบรวมปลายทางสำหรับกลุ่มได้
- summarizingInt/ชนิดจำนวนเต็มยาว/ชนิดทศนิยมคู่ ให้จำนวน ผลรวม ค่าต่ำสุด ค่าสูงสุด และค่าเฉลี่ยในการส่งผ่านครั้งเดียว
- ทั้งหมดทำงานในการส่งผ่านสตรีมครั้งเดียวแบบ O(n)
คำถามที่พบบ่อย
บทเรียน “partitioningBy และ counting” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “partitioningBy และ counting” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Java Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “partitioningBy และ counting”
แบ่งสตรีมออกเป็นสองกลุ่มด้วย partitioningBy และนับองค์ประกอบด้วย counting คุณปฏิบัติ Java Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Java Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Java Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน
บทเรียน “partitioningBy และ counting” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Java Academy นี้ได้ไหม
ได้ บทเรียน Java Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- groupingBy: การจัดหมวดหมู่องค์ประกอบ
- partitioningBy และ counting
- toMap, joining และ summarizing
- การสร้าง Collector แบบกำหนดเอง