المسارات
/
Elm
Elm
/
التمارين
/
أفضل الهدافين
أفضل الهدافين

أفضل الهدافين

تمرين تعلّمي

مقدمة

Dict

في Elm، Dict هو قاموس غير قابل للتغيير يتكوّن من صفر أو أكثر من أزواج المفتاح والقيمة.

تُعالَج القواميس بواسطة دوال وعوامل معرّفة في وحدة Dict.

تُكتب تعليقات النوع الخاصة بالقواميس على النحو التالي:

Dict String (List Int) --> a dict with String keys and List Int values
Dict Int String --> a dict with Int keys and String values

يمكن إنشاء القواميس كما يلي:

empty : Dict Int String
empty = Dict.empty

singleValue = Dict.singleton 5 "Value for key 5" --> Dict Int String

twoValues = Dict.fromList [ ( "Alice", 0 ), ( "Bob", 1 ) ] --> Dict String Int

يمكن استرجاع العناصر باستخدام get. وبما أن المفتاح قد يكون موجودًا في القاموس أو لا، فستكون النتيجة مُغلَّفة داخل Maybe.

alice = Dict.fromList [ ( 0, "Alice" ) ]
keyExists = Dict.get 0 alice --> Just "Alice"
keyNotPresent = Dict.get 1 alice --> Nothing

يمكن إضافة العناصر باستخدام insert. أما العناصر ذات المفاتيح الموجودة بالفعل في القاموس فتُستبدل.

alice = Dict.fromList [ ( "Alice", 0 ) ]
aliceAndBob = Dict.insert "Bob" 1 alice  --> Dict.fromList [ ( "Alice", 0 ), ( "Bob", 1 ) ]
aliceAndAlice = Dict.insert "Alice" 1 alice  --> Dict.fromList [ ( "Alice", 1 ) ]

يمكن تحديث العناصر باستخدام update. إذا لم يكن المفتاح موجودًا، فستُستدعى دالة التحديث بالقيمة Nothing.

alice = Dict.fromList [ ( 0, "Alice" ) ]
aliceUpperCase = Dict.update 0 (Maybe.map String.toUpper) alice --> Dict.fromList [ ( 0, "ALICE" ) ]
aliceNoCase = Dict.update 0 (\_ -> Nothing) alice --> Dict.empty
bobUpperCase = Dict.update 1 (\_ -> Just "BOB") alice --> Dict.fromList [ ( 0, "Alice" ), ( 1, "BOB" ) ]
bobNoCase = Dict.update 1 (\_ -> Nothing) alice --> Dict.fromList [ ( 0, "Alice" ) ]

يمكن إزالة العناصر باستخدام remove. إذا لم يكن المفتاح موجودًا، فلن يحدث أي تغيير.

alice = Dict.fromList [ ( 0, "Alice" ) ]
stillAlice = Dict.remove 1 --> ( 0, "Alice" )
empty = Dict.remove 0 alice --> Dict.empty

يمكن تحويل مصفوفة من أزواج المفتاح والقيمة إلى قاموس باستخدام fromList.

alice = Dict.fromList [ ( 0, "Bob" ), ( 0, "Alice" ) ]
--> True Dict.fromList [ ( 0, "Alice" ) ]

يمكن تحويل العناصر إلى مصفوفة باستخدام toList. وتُرتَّب المصفوفة حسب المفاتيح.

aliceAndBob = Dict.fromList [ ( 1, "Alice" ), ( 0, "Bob" ) ]
bobAndAlice = Dict.toList aliceAndBob
--> [ ( 0, "Bob" ), ( 1, "Alice" ) ]

يمكن إزالة عدة عناصر باستخدام filter.

aliceAndBob = Dict.fromList [ ( "Alice", 1 ), ( "Bob", 0 ) ]
bob = Dict.filter (\name count -> name == "Bob") aliceAndBob --> Dict.fromList [ ( "Bob", 0 ) ]

يمكن تحويل العناصر باستخدام map.

alice = Dict.fromList [ ( "Alice", 0 ) ]
empty = Dict.map (\player count -> count + 1) alice --> Dict.fromList [ ( "Alice", 1 ) ]

يمكن دمج القواميس أو تحويلها باستخدام merge.

aliceAndBob = Dict.fromList [ ( "Alice", 1 ), ( "Bob", 1 ) ]
bobAndCedd = Dict.fromList [ ( "Bob", 1 ), ( "Cedd", 1 ) ]
firstDictCountsDouble = Dict.merge
        -- when only in aliceAndBob
        (\name count mergedCounts -> Dict.insert name (2 * count) mergedCounts)
        -- when in aliceAndBob and bobAndCedd
        (\name aliceAndBobCount bobAndCeddCount mergedCounts -> Dict.insert name (2 * aliceAndBobCount + bobAndCeddCount) mergedCounts)
        -- when only in bobAndCedd
        (\name count mergedCounts -> Dict.insert name count mergedCounts)
        -- the two dicts to merge
        aliceAndBob
        bobAndCedd
        -- the initial state of the merge
        Dict.empty
--> Dict.fromList [ ( "Alice", 2 ), ( "Bob", 3 ), ( "Cedd", 1 ) ]

أي دالة أو عامل يبدو أنه يعدّل القاموس (مثل إضافة عنصر)، فإنه يُرجع في الواقع قاموسًا جديدًا. وعادةً لا يمثّل الأداء مشكلة، لأن طريقة التنفيذ تمنع عمليات التخصيص أو النسخ غير الضرورية.

في Elm، من الأفضل عمومًا استخدام تجريدات ذات مستوى أعلى، مثل Dict.map وDict.filter وDict.merge، بدلًا من تجريدات ذات مستوى أدنى مثل Dict.get وDict.remove، مع أن الأمر يعتمد بالطبع على السياق.

التعليمات

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

PlayerName هو اسم مستعار للنوع String، لجعل الكود أسهل في القراءة، ولتمييز هذا الاستخدام لـ String عن الاستخدامات الأخرى لـ String.

1. تجميع المسجّلين

أولًا، نفّذ updateGoalCountForPlayer لتهيئة عدد أهداف اللاعب أو زيادته. ثم نفّذ دالة aggregateScorers لإحصاء عدد الأهداف التي سجّلها كل لاعب، باستخدام updateGoalCountForPlayer. تأخذ هذه الدالة List PlayerName (أسماء اللاعبين الذين سجّلوا الأهداف، وقد تحتوي على أسماء لاعبين مكرّرة)، وتُرجع Dict PlayerName Int يحتوي على جميع اللاعبين في القائمة مع عدد الأهداف التي سجّلوها.

aggregateScorers [ "Betty", "Cedd", "Betty" ]
--> Dict.fromList [ ( "Betty", 2 ), ( "Cedd", 1 ) ]

2. إزالة اللاعبين غير المهمّين

نفّذ دالة removeInsignificantPlayers لاستبعاد اللاعبين الذين سجّلوا أهدافًا أقل من العتبة.

removeInsignificantPlayers 2 (Dict.fromList [ ( "Betty", 2 ), ( "Cedd", 1 ) ] )
--> Dict.fromList [ ( "Betty", 2 ) ]

3. إعادة تعيين عدد أهداف اللاعب

نفّذ دالة resetPlayerGoalCount لإعادة تعيين عدد الأهداف المسجّلة للاعب إلى صفر.

resetPlayerGoalCount "Cedd" (Dict.fromList [ ( "Betty", 2 ), ( "Cedd", 1 ) ] )
--> Dict.fromList [ ( "Betty", 2 ), ( "Cedd", 0 ) ]

4. تنسيق عدد الأهداف للاعب واحد

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

formatPlayer "Betty" (Dict.fromList [ ( "Betty", 2 ), ( "Cedd", 1 ) ] )
--> "Betty: 2"

5. تنسيق عدد الأهداف لجميع اللاعبين

نفّذ دالة formatPlayers لتنسيق عدد الأهداف لجميع اللاعبين على شكل سلسلة نصية. يجب ترتيب اللاعبين حسب اسم اللاعب.

formatPlayers (Dict.fromList [ ( "Betty", 2 ), ( "Cedd", 1 ) ] )
--> "Betty: 2, Cedd: 1"

6. دمج المباريات

نفّذ دالة combineGames، مع إحصاء العدد الإجمالي للأهداف التي سجّلها كل لاعب في المباراتين.

combine Games
  (Dict.fromList [ ( "Betty", 2 ), ( "Cedd", 1 ) ] )
  (Dict.fromList [ ( "Betty", 2 ), ( "Mario", 3 ) ] )
--> Dict.fromList [ ( "Betty", 4 ), ( "Cedd", 1 ), ( "Mario", 3 ) ]
تعديل عبر GitHub يفتح الرابط في نافذة أو علامة تبويب جديدة
Elm Exercism

مستعد لبدء أفضل الهدافين؟

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