0Pricing
Java Academy · درس

groupingBy: تصنيف العناصر

جمّع عناصر التدفق في خرائط باستخدام دالة تصنيف، وادمجها مع الجامعات اللاحقة

groupingBy: تصنيف العناصر درس مجاني في Java Academy على CoddyKit. هذا هو الدرس 1 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Java Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Java Academy 4 دروس في المجموع.

ما هو groupingBy؟

تُقسّم Collectors.groupingBy() عناصر التدفق إلى Map، بحيث يربط كل مفتاح بقائمة من العناصر المطابقة. وهي المكافئ في التدفقات لعبارة GROUP BY في SQL.

import java.util.*;
import java.util.stream.*;

record Person(String name, String city) {}
List<Person> people = List.of(
    new Person("Alice","NYC"), new Person("Bob","LA"),
    new Person("Carol","NYC"), new Person("Dave","LA"),
    new Person("Eve","Chicago")
);

Map<String, List<Person>> byCity =
    people.stream().collect(Collectors.groupingBy(Person::city));
byCity.forEach((city, ps) -> System.out.println(city + ": " + ps.size()));

الجامع اللاحق: counting

ركّب groupingBy مع جامع لاحق لإجراء التجميع بدلاً من إنشاء قائمة بالعناصر:

Map<String, Long> countByCity =
    people.stream().collect(
        Collectors.groupingBy(Person::city, Collectors.counting())
    );
countByCity.forEach((city, n) -> System.out.println(city + " -> " + n));
// NYC -> 2, LA -> 2, Chicago -> 1

الجامع اللاحق: mapping

استخدم Collectors.mapping() كجامع لاحق لتحويل العناصر قبل جمعها:

Map<String, List<String>> namesByCity =
    people.stream().collect(
        Collectors.groupingBy(
            Person::city,
            Collectors.mapping(Person::name, Collectors.toList())
        )
    );
namesByCity.forEach((city, names) -> System.out.println(city + ": " + names));

الجامع اللاحق: joining

ادمج الأسماء في كل مجموعة ضمن سلسلة نصية واحدة مفصولة بفواصل:

Map<String, String> joinedByCity =
    people.stream().collect(
        Collectors.groupingBy(
            Person::city,
            Collectors.mapping(Person::name, Collectors.joining(", "))
        )
    );
joinedByCity.forEach((city, s) -> System.out.println(city + ": " + s));
// NYC: Alice, Carol

تجميع groupingBy متعدد المستويات

ضمّن استدعاءات groupingBy لإجراء تصنيف متعدد الأبعاد:

record Employee(String name, String dept, String level) {}
List<Employee> emps = List.of(
    new Employee("A","Eng","Junior"), new Employee("B","Eng","Senior"),
    new Employee("C","HR","Junior"), new Employee("D","HR","Senior")
);

Map<String, Map<String, List<Employee>>> grouped =
    emps.stream().collect(
        Collectors.groupingBy(Employee::dept,
            Collectors.groupingBy(Employee::level))
    );
grouped.forEach((dept, levels) -> levels.forEach((level, list) ->
    System.out.println(dept+"/"+level+": "+list.size())));

التحكم في نوع Map

ينتج groupingBy كائن HashMap افتراضيًا. استخدم التحميل الزائد ذي الوسائط الثلاثة لتحديد نوع مختلف من الخرائط، مثل TreeMap للمفاتيح المرتبة:

Map<String, Long> sorted =
    people.stream().collect(
        Collectors.groupingBy(Person::city, TreeMap::new, Collectors.counting())
    );
System.out.println(sorted); // keys in alphabetical order

الجامع اللاحق: averagingInt

احسب المتوسطات لكل مجموعة:

record Product(String category, int price) {}
List<Product> products = List.of(
    new Product("A",10), new Product("A",20),
    new Product("B",15), new Product("B",25)
);

Map<String, Double> avgPrice =
    products.stream().collect(
        Collectors.groupingBy(Product::category,
            Collectors.averagingInt(Product::price))
    );
avgPrice.forEach((cat, avg) -> System.out.printf("%s: %.1f%n", cat, avg));

الجامع اللاحق: toUnmodifiableList

استخدم Collectors.toUnmodifiableList() كجامع لاحق لإنشاء مجموعات غير قابلة للتعديل:

Map<String, List<String>> immutable =
    people.stream().collect(
        Collectors.groupingBy(Person::city,
            Collectors.mapping(Person::name, Collectors.toUnmodifiableList()))
    );
// Attempting to modify throws UnsupportedOperationException

حالة استخدام فعلية: ملخص الطلبات

جمّع الطلبات حسب الحالة واجمع المبالغ لكل مجموعة:

record Order(String status, double amount) {}
List<Order> orders = List.of(
    new Order("PAID", 50.0), new Order("PENDING", 30.0),
    new Order("PAID", 75.0), new Order("CANCELLED", 20.0)
);

Map<String, Double> totalByStatus =
    orders.stream().collect(
        Collectors.groupingBy(Order::status,
            Collectors.summingDouble(Order::amount))
    );
totalByStatus.forEach((s, t) -> System.out.printf("%s: $%.2f%n", s, t));

اعتبارات الأداء

يجمع groupingBy جميع العناصر في الذاكرة. بالنسبة إلى مجموعات البيانات الكبيرة جدًا، فكّر في معالجة البيانات على دفعات أو استخدام GROUP BY على مستوى قاعدة البيانات. ويُشغَّل الجامع اللاحق لكل عنصر، لذا اجعله خفيفًا لتجنب سلوك O(n²).

الدمج مع filter وsorted

اربط عمليات التدفق قبل التجميع لتصفية البيانات أو ترتيبها مسبقًا:

Map<String, Long> activeCities =
    people.stream()
          .filter(p -> !p.city().equals("Chicago"))
          .collect(Collectors.groupingBy(Person::city, Collectors.counting()));
System.out.println(activeCities); // {NYC=2, LA=2}

تحقق سريع

ما النوع الذي ينتجه Collectors.groupingBy(Person::city) عند استخدامه مع collect()؟

مراجعة: groupingBy

أهم النقاط:

  • groupingBy(classifier) → Map<K, List<T>>
  • ركّبه مع الجوامع اللاحقة: counting وmapping وjoining وsummarizing
  • ضمّن groupingBy لإجراء تصنيف متعدد الأبعاد
  • استخدم التحميل الزائد ذي الوسائط الثلاثة للتحكم في نوع الخريطة الناتجة، مثل TreeMap

الأسئلة الشائعة

هل درس «groupingBy: تصنيف العناصر» مجاني؟

نعم — نص درس «groupingBy: تصنيف العناصر» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Java Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Java Academy 4 دروس في المجموع.

ماذا ستتعلم في «groupingBy: تصنيف العناصر»؟

جمّع عناصر التدفق في خرائط باستخدام دالة تصنيف، وادمجها مع الجامعات اللاحقة تتمرن على Java Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Java Academy؟

لا تُشترط خبرة سابقة. Java Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 1 من أصل 4.

كم من الوقت يستغرق درس «groupingBy: تصنيف العناصر»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Java Academy هذا؟

نعم. كل درس في Java Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. groupingBy: تصنيف العناصر
  2. partitioningBy وcounting
  3. toMap وjoining وsummarizing
  4. إنشاء جامع مخصص
← العودة إلى Java Academy