partitioningBy وcounting
قسّم التدفق إلى مجموعتين باستخدام partitioningBy، واحسب العناصر باستخدام counting
partitioningBy وcounting درس مجاني في Java Academy على CoddyKit. هذا هو الدرس 2 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 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 العناصر إلى مجموعتين بالضبط (true/false)
- يكون المفتاحان موجودين دائمًا، لذلك لا يوجد خطر NPE بخلاف groupingBy
- يحسب counting() عدد العناصر؛ استخدمه كجامع لاحق للمجموعات
- يوفّر summarizingInt/Long/Double العدد والمجموع والقيمة الصغرى والقيمة الكبرى والمتوسط في مرور واحد
- تعمل جميعها في مرور واحد على التدفق بتعقيد O(n)
الأسئلة الشائعة
هل درس «partitioningBy وcounting» مجاني؟
نعم — نص درس «partitioningBy وcounting» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Java Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Java Academy 4 دروس في المجموع.
ماذا ستتعلم في «partitioningBy وcounting»؟
قسّم التدفق إلى مجموعتين باستخدام partitioningBy، واحسب العناصر باستخدام counting تتمرن على Java Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ Java Academy؟
لا تُشترط خبرة سابقة. Java Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 4.
كم من الوقت يستغرق درس «partitioningBy وcounting»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Java Academy هذا؟
نعم. كل درس في Java Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- groupingBy: تصنيف العناصر
- partitioningBy وcounting
- toMap وjoining وsummarizing
- إنشاء جامع مخصص