المسارات
/
jq
jq
/
التمارين
/
إحصاءات الدرجات
إحصاءات الدرجات

إحصاءات الدرجات

تمرين تعلّمي

مقدمة

الاختزال

لنفترض أننا نريد جمع عناصر مصفوفة من الأعداد. وهناك طرق عديدة لتحقيق هذا الهدف.

  • في كثير من اللغات، تُصاغ هذه المسألة على هيئة حلقة مع متغير مراكم.

  • ويمكن كتابة هذه المسألة على هيئة دالة عودية. وبصيغة الكود الزائف، قد يكون لدينا ما يلي.

    function Add(X, Sum=0):
      if X is empty then
        return Sum
      else
        return Add(rest(X), Sum + first(X))
      end
    end
    

    ويمكن أيضًا وصف هذه الطريقة في تقسيم المسألة إلى أجزاء أصغر بأنها "اختزال نحو الحالة الأساسية".

الاختزال طريقة لدمج جميع عناصر بنية بيانات في قيمة واحدة. تمرّ العملية على بنية البيانات عنصرًا عنصرًا، فتطبّق دالة على كل عنصر لتحديث النتيجة المتراكمة.

في jq، تُنفَّذ هذه العملية عبر مرشّح reduce. وفي لغات أخرى قد تُسمّى "fold" أو "fold-left" أو "inject" أو "aggregate".

يبدو تعبير reduce في jq على النحو التالي.

reduce STREAM_EXPRESSION as $var (INITIAL_VALUE; UPDATE_EXPRESSION)
  • STREAM_EXPRESSION هو تدفّق من العناصر، يُخزَّن كل عنصر منه في المتغير $var بالتبادل.
  • INITIAL_VALUE هو القيمة الابتدائية للنتيجة المتراكمة (وتُعرف بـ"المراكم").
  • يدمج UPDATE_EXPRESSION ("يطوي") القيمة الحالية ($var) في المراكم.
    • في سياق هذا التعبير، ترمز . إلى قيمة المراكم.
    • يُخزَّن ناتج التعبير في المراكم لاستخدامه في التكرار التالي.
    • بعد التكرار الأخير، تكون النتيجة المتراكمة هي ناتج reduce.

لنلقِ نظرة على مثال: جمع الأعداد في مصفوفة. مرشّح add يفعل هذا تمامًا، لكننا سنرى كيف ننفّذه.

إذا استخدمنا [10, 20, 30, 40] كمدخل، واتخذنا الصفر حالةً ابتدائية، فهذا ما تبدو عليه كل خطوة.

# الحالة العنصر الدمج النتيجة
1 0 10 0 + 10 10
2 10 20 10 + 20 30
3 30 30 30 + 30 60
4 60 40 60 + 40 100

في صيغة jq، يبدو هذا كما في الكود التالي.

0 + 10 | . + 20 | . + 30 | . + 40

ويمكننا التعبير عن ذلك باستخدام مرشّح reduce.

[10, 20, 30, 40] | reduce .[] as $n (0; . + $n)     # => 100
Note

الدالة المدمجة add هي في الحقيقة منفَّذة باستخدام reduce، لكنها تستخدم "null" كحالة ابتدائية (يمكن إضافة أي نوع من البيانات إلى null).

def add: reduce .[] as $x (null; . + $x);

بعض الأمور التي يجب أخذها في الاعتبار

  • في تعبير الاختزال، ترمز . إلى المراكم. وإذا كان المدخل كائنًا تحتاج إلى الرجوع إليه داخل دالة الاختزال، فعليك تخزينه في متغير.

    {"apple": 10, "banana": 16, "carrot": 4}
    | . as $obj
    | reduce (keys | .[]) as $key (0; . + $obj[$key])     # => 30
    
  • يمكن أن يكون المراكم من أي نوع من البيانات. فمثلًا، قد ترغب في عكس ترتيب مصفوفة.

    ["A", "B", "C", "D"]
    | reduce .[] as $elem ([]; [$elem] + .)       # => ["D", "C", "B", "A"]
    

التعليمات

أنت مدرّس. في نهاية العام، أنشأت درجة رقمية لكل طالب من طلابك. والآن عليك تحويلها إلى تقدير حرفي، وإحصاء عدد الطلاب الذين حصلوا على كل تقدير حرفي

1. حوّل درجة رقمية إلى تقدير حرفي

دالة letter_grade تأخذ درجة رقمية كمدخل، وتُرجع التقدير الحرفي. استخدم هذه النطاقات:

التقدير الدرجة
A 90% - 100%
B 80% - 89%
C 70% - 79%
D 60% - 69%
F 0% - 59%

مثال:

75 | letter_grade   # => "C"

2. أحصِ عدد الطلاب لكل تقدير حرفي

الدالة count_letter_grades تأخذ كائنًا يربط أسماء الطلاب بدرجاتهم. وستُرجع كائنًا يربط كل تقدير حرفي بعدد الطلاب الحاصلين على ذلك التقدير.

مثال:

{"Joe": 78, "Jane": 93, "Richard": 72} | count_letter_grades
# => {"A": 1, "B": 0, "C": 2, "D": 0, "F": 0}

هناك عدة أساليب لحل هذه المسألة. استخدم المرشّح reduce للتدريب.

تعديل عبر GitHub يفتح الرابط في نافذة أو علامة تبويب جديدة
jq Exercism

مستعد لبدء إحصاءات الدرجات؟

سجّل في Exercism لتتعلّم وتتقن jq عبر 12 مفهومًا75 تمرينًا، وإرشاد بشري حقيقي، وكل ذلك مجانًا.