Gotta Snatch'Em All

Gotta Snatch'Em All

تمرين تعلّمي

مقدمة

مجموعات MapSet

MapSet مجموعة من القيم الفريدة، وهي تمثّل المجموعات في Elixir. يمكنها أن تحتوي قيمًا من أي نوع، ومن دون أي مفهوم للترتيب.

لاحظ أن وحدة Set موجودة أيضًا، لكن استخدامها مهجور لصالح MapSet.

يمكنك إنشاء المجموعات باستخدام MapSet.new/0 وMapSet.new/1 وMapSet.new/2، وتحويلها إلى قوائم باستخدام MapSet.to_list/1.

MapSet.new()
# => MapSet.new([])

MapSet.new([2, 3, 3, 3, 1, 1, 2, "hello"])
# => MapSet.new([1, 2, 3, "hello"])

MapSet.new([2, 3, 3, 3, 1, 1, 2], fn n -> 10 * n end)
# => MapSet.new([10, 20, 30])

[2, 3, 3, 3, 1, 1, 2] |> MapSet.new() |> MapSet.to_list()
# => [1, 2, 3]

لاحظ أنه بما أن مجموعات MapSet ليس لها مفهوم للترتيب، فليس مضمونًا أن تُرجع MapSet.to_list/1 قائمة مرتّبة.

يمكنك إضافة العناصر أو حذفها باستخدام MapSet.put/2 وMapSet.delete/2.

يمكنك الاستعلام عن محتويات مجموعة باستخدام الدوال MapSet.size/1 وMapSet.member?/2، ومقارنة المجموعات باستخدام MapSet.equal?/2 وMapSet.subset?/2 وMapSet.disjoint?/2.

a = MapSet.new([1, 10])
b = MapSet.new([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])

MapSet.size(b)
# => 10

MapSet.member?(a, 10)
# => true

MapSet.subset?(a, b)
# => true

MapSet.disjoint?(a, b)
# => false

يمكن دمج مجموعات MapSet باستخدام MapSet.union/2 وMapSet.intersection/2 وMapSet.difference/2 وMapSet.symmetric_difference/2.

a = MapSet.new([1, 10, 100])
b = MapSet.new([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])

MapSet.union(a, b)
# => MapSet.new([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 100])

MapSet.intersection(a, b)
# => MapSet.new([1, 10])

MapSet.difference(a, b)
# => MapSet.new([100])

MapSet.difference(b, a)
# => MapSet.new([2, 3, 4, 5, 6, 7, 8, 9])

MapSet.symmetric_difference(b, a)
# => MapSet.new([2, 3, 4, 5, 6, 7, 8, 9, 100])

يمكنك تصفية المجموعات وتقسيمها باستخدام MapSet.filter/2 وMapSet.reject/2 وMapSet.split_with/2.

a = MapSet.new([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
even = fn n -> rem(n, 2) == 0 end

MapSet.filter(a, even)
# => MapSet.new([2, 4, 6, 8, 10])

MapSet.reject(a, even)
# => MapSet.new([1, 3, 5, 7, 9])

MapSet.split_with(a, even)
# => {MapSet.new([2, 4, 6, 8, 10]), MapSet.new([1, 3, 5, 7, 9])}

التعليمات

يبدو أن حنينك إلى بطاقات Blorkemon™️ لا يُظهر أي علامة على التباطؤ، حتى إنك بدأت بجمعها من جديد، وتستقطب أصدقاءك لينضموا إليك.

في هذا التمرين، تُمثَّل مجموعة البطاقات بواسطة MapSet، لأن البطاقات المكررة لا أهمية لها عندما يكون هدفك الحصول على جميع البطاقات الموجودة.

1. ابدأ مجموعة

أنت تتوق حقًا إلى أن ينضم أصدقاؤك إلى جنون Blorkemon™️، وأفضل طريقة هي أن تبدأ مجموعتهم بمنحهم بطاقة واحدة.

نفّذ GottaSnatchEmAll.new_collection، التي تحوّل بطاقة إلى مجموعة.

GottaSnatchEmAll.new_collection("Newthree")
# => MapSet.new(["Newthree"])

2. نمِّ المجموعة

بمجرد أن تحصل على مجموعة، تصير لها حياة خاصة بها، ولا بد أن تنمو.

نفّذ GottaSnatchEmAll.add_card، التي تأخذ بطاقة ومجموعة، وتُرجع زوجًا من قيمتين: قيمة منطقية تشير إلى ما إذا كانت البطاقة موجودة في المجموعة بالفعل، والمجموعة مع البطاقة المضافة.

GottaSnatchEmAll.add_card("Scientuna", MapSet.new(["Newthree"]))
# => {false, MapSet.new(["Newthree", "Scientuna"])}

3. ابدأ المقايضة

الآن بعد أن عاد أصدقاؤك إلى جنون Blorkemon™️، يمكنك الاستفادة من ذلك لتنمية مجموعتك عبر مقايضة البطاقات.

ليست كل مقايضة جديرة بالقيام بها، أو ممكنة أصلًا. لا يمكنك مقايضة بطاقة لا تملكها، ولا ينبغي أن تقايض بطاقة بأخرى تملكها بالفعل.

نفّذ GottaSnatchEmAll.trade_card، التي تأخذ بطاقتين للمقايضة (بطاقتك وبطاقتهم) ومجموعتك الحالية. القيمة المُرجَعة هي زوج من قيمتين: قيمة منطقية تبيّن ما إذا كانت المقايضة ممكنة وجديرة بالقيام بها، والمجموعة التي ستنتهي إليها إذا أجريت المقايضة (حتى لو لم تكن ممكنة فعليًا).

GottaSnatchEmAll.trade_card("Scientuna", "Newthree", MapSet.new(["Scientuna"]))
# => {true, MapSet.new(["Newthree"])}

4. واحدة فقط من كل بطاقة

تجد مخزونًا قديمًا من البطاقات في سوق للسلع المستعملة. عليك أن ترتّب البطاقات وتزيل المكرر منها لتقارن المصفوفة بمجموعتك.

نفّذ GottaSnatchEmAll.remove_duplicates التي ترتّب مصفوفة من البطاقات وتُرجع مصفوفة من البطاقات المرتّبة والفريدة.

GottaSnatchEmAll.remove_duplicates(["Newthree", "Newthree", "Newthree", "Scientuna"])
# => ["Newthree", "Scientuna"]

5. البطاقات التي لا يملكونها

حان وقت الاعتزاز بمجموعتك.

نفّذ GottaSnatchEmAll.extra_cards، التي تأخذ مجموعتك ومجموعة أخرى، وتُرجع عدد البطاقات التي لا تملكها المجموعة الأخرى.

GottaSnatchEmAll.extra_cards(MapSet.new(["Scientuna"]), MapSet.new(["Newthree", "Scientuna"]))
# => 0

6. البطاقات التي يملكونها جميعًا

تجتمع أنت وأصدقاؤك المتحمسون لـ Blorkemon™️ وتتساءلون عن البطاقات الأكثر شيوعًا.

نفّذ GottaSnatchEmAll.boring_cards، التي تأخذ مصفوفة من المجموعات وتُرجع مصفوفة من البطاقات المرتّبة التي تملكها جميع المجموعات.

GottaSnatchEmAll.boring_cards([MapSet.new(["Scientuna"]), MapSet.new(["Newthree", "Scientuna"])])
# => ["Scientuna"]

7. كل البطاقات

هل تملك أنت وأصدقاؤك مجتمعين كل بطاقات Blorkemon™️؟

نفّذ GottaSnatchEmAll.total_cards، التي تأخذ مصفوفة من المجموعات وتُرجع العدد الإجمالي للبطاقات المختلفة في جميع المجموعات.

GottaSnatchEmAll.total_cards([MapSet.new(["Scientuna"]), MapSet.new(["Newthree", "Scientuna"])])
# => 2

8. اللمعان للفوز

سيأتي ابن أخيك لزيارتك قريبًا، وتشعر برغبة في إبهاره. الأطفال يحبون الأشياء اللامعة، أليس كذلك؟ يمكن أن تكون بطاقات Blorkemon™️ لامعة!

نفّذ GottaSnatchEmAll.split_shiny_cards، التي تأخذ مجموعة وتُرجع زوجًا من مصفوفتين من البطاقات المرتّبة: واحدة تضم كل البطاقات التي تبدأ بـ "Shiny" وأخرى بالبطاقات الأخرى.

GottaSnatchEmAll.split_shiny_cards(MapSet.new(["Newthree", "Scientuna", "Shiny Scientuna"]))
# => {["Shiny Scientuna"], ["Newthree", "Scientuna"]}
تعديل عبر GitHub يفتح الرابط في نافذة أو علامة تبويب جديدة
Elixir Exercism

مستعد لبدء Gotta Snatch'Em All؟

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