تناول مفهوم Pairs and Dicts أساسيات نوع القواميس في Julia.
ولأن كائنات Dict نوع مهم وكثير الاستخدام من أنواع المجموعات، فإن هناك أيضًا دوال كثيرة للتعامل معها.
أبسط طريقة لاسترجاع مدخل هي استخدام مفتاحه (كما في كثير من اللغات).
لكن طلب مفتاح غير موجود يؤدي إلى KeyError.
julia> d = Dict(i => ('a':'c')[i] for i in 1:3)
Dict{Int64, Char} with 3 entries:
2 => 'b'
3 => 'c'
1 => 'a'
julia> d[2]
'b': ASCII/Unicode U+0062 (category Ll: Letter, lowercase)
# missing key
julia> d[4]
ERROR: KeyError: key 4 not found
يمكننا التحقق من وجود المفتاح قبل محاولة استرجاعه (باستخدام شيء مثل haskey(d, 4))، لكن قد يكون من المفيد الحصول مباشرة على قيمة افتراضية للمفاتيح غير الموجودة.
لهذا الغرض، لدينا الدالة get() وصيغتها المعدِّلة get!().
ويختلفان في ما إذا كان المفتاح «غير الموجود» يُضاف إلى Dict أم لا.
julia> get(d, 4, '!')
'!': ASCII/Unicode U+0021 (category Po: Punctuation, other)
# get() leaves Dict unchanged
julia> d
Dict{Int64, Char} with 3 entries:
2 => 'b'
3 => 'c'
1 => 'a'
julia> get!(d, 4, '!')
'!': ASCII/Unicode U+0021 (category Po: Punctuation, other)
# get!() adds new key to Dict
julia> d
Dict{Int64, Char} with 4 entries:
4 => '!'
2 => 'b'
3 => 'c'
1 => 'a'
رأينا في المفهوم السابق أن delete!() تحذف مدخلًا حسب مفتاحه.
ويمكن الجمع بين ذلك واسترجاع القيمة باستخدام الدالة pop!().
julia> d
Dict{Int64, Char} with 4 entries:
4 => '!'
2 => 'b'
3 => 'c'
1 => 'a'
# popped value is returned
julia> pop!(d, 3)
'c': ASCII/Unicode U+0063 (category Ll: Letter, lowercase)
# Dict is shrunk
julia> d
Dict{Int64, Char} with 3 entries:
4 => '!'
2 => 'b'
1 => 'a'
عند التكرار على Dict، يكون السلوك الافتراضي هو إعطاء أزواج key => value.
ويمكن الوصول إلى مكوّني كل زوج بالتسمية المعتادة .first و .second.
# d is from the previous example
julia> [(kv.first, kv.second) for kv in d]
3-element Vector{Tuple{Int64, Char}}:
(4, '!')
(2, 'b')
(1, 'a')
وغالبًا ما نريد استخدام المفاتيح فقط أو القيم فقط، وهذا أمر سهل.
julia> [k for k in keys(d)]
3-element Vector{Int64}:
4
2
1
julia> [v for v in values(d)]
3-element Vector{Char}:
'!': ASCII/Unicode U+0021 (category Po: Punctuation, other)
'b': ASCII/Unicode U+0062 (category Ll: Letter, lowercase)
'a': ASCII/Unicode U+0061 (category Ll: Letter, lowercase)
قد يكون دمج كائنين من Dict مفيدًا، لكن يجب أن نكون واضحين بشأن ما ننوي فعله بالمفاتيح الموجودة في أكثر من مُدخل واحد.
تدمج الدالتان merge() و merge!() أي عدد من كائنات Dict المُمرَّرة من اليسار إلى اليمين.
تُستبدل قيم المفاتيح الموجودة ببساطة، لذا فإن Dict الأقرب إلى اليمين هو الذي «يفوز».
julia> d3 = Dict("color" => "red", "shape" => "circle")
Dict{String, String} with 2 entries:
"shape" => "circle"
"color" => "red"
julia> d4 = Dict("color" => "blue", "coords" => (3, 2))
Dict{String, Any} with 2 entries:
"color" => "blue"
"coords" => (3, 2)
# color from d3 is lost
julia> merge(d3, d4)
Dict{String, Any} with 3 entries:
"shape" => "circle"
"color" => "blue"
"coords" => (3, 2)
تتيح لنا الدالتان mergewith() و mergewith!() تمرير دالة كوسيط أول لتحديد كيفية دمج المفاتيح المتكررة.
والجمع مثال بسيط على ذلك.
julia> d5 = Dict("color" => "red", "area" => 3)
Dict{String, Any} with 2 entries:
"area" => 3
"color" => "red"
julia> d6 = Dict("shape" => "circle", "area" => 5)
Dict{String, Any} with 2 entries:
"shape" => "circle"
"area" => 5
# area values are added, not overwritten
julia> mergewith(+, d5, d6)
Dict{String, Any} with 3 entries:
"shape" => "circle"
"area" => 8
"color" => "red"
لاحظ أن دوال mergewith مثال جيد على الدوال عالية الرتبة في العمل.
وظّفتك للتو شركة Mecha Munch™، وهي شركة لأتمتة التسوق في البقالة، للعمل على تطبيق الطلبات الخاص بها. فريقك مكلّف ببناء MVP (منتج أدنى قابل للتطبيق) يدير كل أنشطة عربة التسوق الأساسية، ويتيح للمستخدمين إضافة طلبات البقالة وإزالتها وترتيبها. لحسن الحظ، هناك فريق آخر يتولى كل وظائف الأموال والدفع!
ينبغي أن يتيح المنتج الأدنى القابل للتطبيق للمستخدم إضافة أصناف إلى عربة تسوقه. قد يكون هذا صنفًا واحدًا أو عدة أصناف دفعة واحدة. وبما أن هذا منتج أدنى قابل للتطبيق، فإن كمية الصنف تُشار إليها بـ_التكرار_. إذا أراد المستخدم إضافة برتقالتين، فستظهر 'Oranges' مرتين في المدخل القابل للتكرار. وإذا كان الصنف موجودًا بالفعل في عربة المستخدم، فينبغي زيادة كميته فيها بمقدار 1. أما إذا كان الصنف جديدًا على العربة، فيُضاف بكمية مقدارها 1.
أنشئ الدالة add_items!(<cart>, <items>) التي تأخذ قاموس العربة وكائنًا قابلًا للتكرار من الأصناف المطلوب إضافتها كوسائط.
ينبغي أن تُرجع قاموس عربة التسوق المُحدَّث للمستخدم.
julia> additems!(Dict("Banana" => 3, "Apple" => 2, "Orange" => 1),
("Apple", "Apple", "Orange", "Apple", "Banana"))
Dict{String, Int64} with 3 entries:
"Apple" => 5
"Orange" => 2
"Banana" => 4
julia> additems!(Dict("Banana" => 3, "Apple" => 2, "Orange" => 1),
["Banana", "Orange", "Blueberries", "Banana"])
Dict{String, Int64} with 4 entries:
"Blueberries" => 1
"Apple" => 2
"Orange" => 2
"Banana" => 5
يحتوي التطبيق على قسم "الأفكار" مملوء بوصفات جاهزة من مطابخ متنوعة. ويمكن للمستخدم اختيار أي وصفة من هذه الوصفات وإضافة جميع مكوناتها إلى عربة تسوقه تلقائيًا. وقد طلب منك مدير المشروع إيجاد أسلوب لتحرير وصفات "الأفكار" هذه، لأن فريق المحتوى يغيّر المكونات والكميات باستمرار.
أنشئ الدالة update_recipes!(<ideas>, <updates>) التي تأخذ قاموس "الأفكار" وقاموسًا بتحديثات الوصفات كوسائط.
ينبغي أن تُرجع الدالة قاموس "الأفكار" المُحدَّث.
julia>update_recipes!(
Dict("Banana Bread" => Dict("Banana" => 1, "Apple" => 1, "Walnuts" => 1, "Flour" => 1, "Eggs" => 2, "Butter" => 1),
"Raspberry Pie" => Dict("Raspberry" => 1, "Orange" => 1, "Pie Crust" => 1, "Cream Custard" => 1)),
Dict("Banana Bread" => Dict("Banana" => 4, "Walnuts" => 2, "Flour" => 1, "Butter" => 1, "Milk" => 2, "Eggs" => 3))
)
Dict{String, Dict{String, Int64}} with 2 entries:
"Raspberry Pie" => Dict("Cream Custard"=>1, "Raspberry"=>1, "Orange"=>1, "Pie Crust"=>1)
"Banana Bread" => Dict("Eggs"=>3, "Flour"=>1, "Milk"=>2, "Butter"=>1, "Walnuts"=>2, "Banana"=>4)
julia> update_recipes!(
Dict("Banana Bread" => Dict("Banana" => 1, "Apple" => 1, "Walnuts" => 1, "Flour" => 1, "Eggs" => 2, "Butter" => 1),
"Raspberry Pie" => Dict("Raspberry" => 1, "Orange" => 1, "Pie Crust" => 1, "Cream Custard" => 1),
"Pasta Primavera" => Dict("Eggs" => 1, "Carrots" => 1, "Spinach" => 2, "Tomatoes" => 3, "Parmesan" => 2, "Milk" => 1, "Onion" => 1)),
Dict("Raspberry Pie" => Dict("Raspberry" => 3, "Orange" => 1, "Pie Crust" => 1, "Cream Custard" => 1, "Whipped Cream" => 2),
"Pasta Primavera" => Dict("Eggs" => 1, "Mixed Veggies" => 2, "Parmesan" => 2, "Milk" => 1, "Spinach" => 1, "Bread Crumbs" => 1),
"Blueberry Crumble" => Dict("Blueberries" => 2, "Whipped Creme" => 2, "Granola Topping" => 2, "Yogurt" => 3))
)
Dict{String, Dict{String, Int64}} with 4 entries:
"Raspberry Pie" => Dict("Raspberry"=>3, "Orange"=>1, "Pie Crust"=>1, "Cream Custard"=>1, "Whipped Cream"=>2)
"Pasta Primavera" => Dict("Eggs"=>1, "Mixed Veggies"=>2, "Parmesan"=>2, "Milk"=>1, "Spinach"=>1, "Bread Crumbs"=>1)
"Blueberry Crumble" => Dict("Blueberries"=>2, "Whipped Creme"=>2, "Granola Topping"=>2, "Yogurt"=>3)
"Banana Bread" => Dict("Banana"=>1, "Apple"=>1, "Walnuts"=>1, "Flour"=>1, "Eggs"=>2, "Butter"=>1)
يحتاج التطبيق إلى إرسال عربة مستخدم معيّن إلى المتجر لتجهيز الطلب. غير أن المتسوقين في المتجر بحاجة إلى معرفة مكان وجود الصنف عبر رمز مميّز للممر. ولهذا يجب ترتيب "عربة التجهيز" وفقًا لرموز ممرات الأصناف، لمساعدة المتسوقين على العمل بكفاءة أكبر.
أنشئ الدالة send_to_store(<cart>, <aislecodes>) التي تأخذ عربة تسوق المستخدم وقاموسًا يحتوي على أرقام ممرات المتجر.
ينبغي أن تُرجع الدالة "عربة تجهيز" مدمجة تحتوي على زوج aislecode => quantity لكل صنف يطلبه العميل.
وينبغي أن تظهر الأصناف بترتيب رموز ممراتها.
julia> cart = Dict("Orange" => 1, "Milk" => 2, "Banana" => 3, "Apple" => 2, "Chocolate" => 2);
julia> aislecodes = Dict("Orange" => 2.4, "Milk" => 3.3, "Banana" => 2.6, "Apple" => 2.2, "Chocolate" => 5.7);
julia> send_to_store(cart, aislecodes)
5-element Vector{Pair{Float64, Int64}}:
2.2 => 2
2.4 => 1
2.6 => 3
3.3 => 2
5.7 => 2
لا يستطيع التطبيق أن يرسل طلبات العملاء بلا نهاية. ففي النهاية ستنفد منتجات متنوعة من المتجر. لذلك يحتاج منتجك الأدنى القابل للتطبيق إلى تحديث مخزون المتجر في كل مرة يرسل فيها المستخدم طلبه إلى المتجر. وإلا سيطلب العملاء منتجات غير متاحة فعلًا.
أنشئ الدالة update_store_inventory!(<inventory>, <cart>) التي تأخذ cart وinventory.
ينبغي أن تُنقص الدالة كميات مخزون المتجر بمقدار العدد "المطلوب" في cart، ثم تُرجع قاموسًا بالأصناف التي نفد مخزونها (أي التي وصلت إلى 0).
julia> inventory = Dict("Banana" => 15, "Apple" => 12, "Orange" => 1, "Milk" => 4);
julia> cart = Dict("Orange" => 1, "Milk" => 2, "Banana" => 3, "Apple" => 2);
julia> update_store_inventory!(inventory, cart)
Dict{String, Int64} with 1 entry:
"Orange" => 0
julia> inventory
Dict{String, Int64} with 4 entries:
"Milk" => 2
"Apple" => 10
"Orange" => 0
"Banana" => 12
إضافة إلى تحديث المخزون، يمكن لتطبيقك المساعدة في إعادة تخزينه. ينبغي أن يكون منتجك الأدنى قابلًا لتحضير طلب مصغّر بأي أصناف نفد مخزونها بعد طلب العميل. سيساعد ذلك في تبسيط إطلاق طلب كبير. علاوة على ذلك، توجد أحيانًا أصناف ترويجية لفترة محدودة غير مدرجة في قائمة المخزون. وإذا نفدت هذه الأصناف قبل انتهاء فترة الترويج، فهذا دليل على شعبيتها، ويمكن إضافتها إلى قائمة المخزون.
أنشئ الدالة reorder!(<outofstock>, <stock>) التي تأخذ outofstock وstock.
يحتوي قاموس stock على أصناف المخزون القياسية وكميات إعادة طلبها.
وقاموس outofstock هو ناتج update_store_inventory!، أي قاموس بالأصناف التي كميتها صفر.
ينبغي تحديث كميات outofstock لتطابق تلك الموجودة في stock ثم إرجاعها.
كذلك، ينبغي إضافة أي أصناف في outofstock غير موجودة في stock إلى stock بكمية افتراضية مقدارها 100.
julia> inventory = Dict("Banana" => 15, "Apple" => 12, "Orange" => 1, "Milk" => 4, "Chocolate" => 2);
julia> cart = Dict("Orange" => 1, "Milk" => 2, "Banana" => 3, "Apple" => 2, "Chocolate" => 2);
julia> stock = Dict("Banana" => 150, "Apple" => 120, "Orange" => 120, "Milk" => 45);
julia> outofstock = update_store_inventory!(inventory, cart)
Dict{String, Int64} with 1 entry:
"Orange" => 0
"Chocolate" => 0
julia> reorder!(outofstock, stock)
Dict{String, Int64} with 1 entry:
"Orange" => 120
"Chocolate" => 100
julia> stock
Dict{String, Int64} with 5 entries:
"Milk" => 45
"Apple" => 120
"Chocolate" => 100
"Orange" => 120
"Banana" => 150
سجّل في Exercism لتتعلّم وتتقن Julia عبر 35 مفهومًا128 تمرينًا، وإرشاد بشري حقيقي، وكل ذلك مجانًا.