Clojure:كيف يمكنني التقدم بطلب وظيفة إلى مجموعة فرعية من الإدخالات في تجزئة الخريطة ؟
سؤال
أنا لا Clojure و محاولة معرفة كيفية القيام بذلك.
أريد إنشاء تجزئة جديدة-خريطة على مجموعة من المفاتيح في تجزئة الخريطة ينطبق وظيفة العناصر.ما هي أفضل طريقة للقيام بذلك ؟
(let
[my-map {:hello "World" :try "This" :foo "bar"}]
(println (doToMap my-map [:hello :foo] (fn [k] (.toUpperCase k)))
وهذا ينبغي أن يؤدي ثم الخريطة مع شيء من هذا القبيل
{:hello "WORLD" :try "This" :foo "BAR"}
المحلول
(defn do-to-map [amap keyseq f] (reduce #(assoc %1 %2 (f (%1 %2))) amap keyseq))
تفصيل:
فإنه يساعد على نظرة من الداخل إلى الخارج.في Clojure ، تجزئة-خرائط تتصرف مثل الوظائف ؛ إذا كنت اسميهم وظيفة مع مفتاح كحجة القيمة المرتبطة مع هذا المفتاح هو عاد.بحيث تعطى مفتاح واحد ، القيمة الحالية لهذا الرئيسية يمكن الحصول عليها عن طريق:
(some-map some-key)
ونحن نريد أن تأخذ القيم القديمة وتغييرها إلى قيم جديدة من خلال استدعاء بعض من وظيفة f
عليها.بحيث تعطى مفتاح واحد ، القيمة الجديدة سوف تكون:
(f (some-map some-key))
نحن نريد أن نضم هذه القيمة الجديدة مع هذا المفتاح في تجزئة الخريطة "استبدال" القيمة القديمة.هذا هو ما assoc
لا:
(assoc some-map some-key (f (some-map some-key)))
("استبدال" في ذعر ونقلت لأننا لا تحور واحد تجزئة الخريطة الكائن ؛ نحن عودته جديدة ثابتة أو تتغير تجزئة الخريطة الكائنات في كل مرة ندعو assoc
.هذا لا يزال سريعة وفعالة في Clojure لأن تجزئة-خرائط المستمر وتبادل هيكل عند assoc
لهم.)
نحن بحاجة إلى مرارا وتكرارا assoc
القيم الجديدة على الخريطة, مفتاح واحد في وقت واحد.لذلك نحن بحاجة إلى نوع من حلقات بناء.ما نريده هو أن تبدأ مع الأصلي تجزئة الخريطة مفتاح واحد ، ثم "تحديث" قيمة هذا المفتاح.ثم نأخذ جديدة تجزئة الخريطة الرئيسية التالية ، و "التحديث" قيمة هذا المفتاح التالي.و نكرر هذا كل مفتاح واحد في وقت واحد ، وأخيرا إعادة تجزئة-خريطة لقد "المتراكمة".هذا هو ما reduce
لا.
- أول حجة
reduce
هي الدالة التي تأخذ حجتين:في "المجمع" القيمة هي قيمة الإبقاء على "تحديث" مرارا وتكرارا ؛ و حجة واحدة المستخدمة في التكرار واحد للقيام ببعض من التراكم. - الحجة الثانية أن
reduce
هو القيمة الأولية كما مر أول حجة هذاfn
. - الحجة الثالثة أن
reduce
هو مجموعة من الحجج إلى تمرير الوسيطة الثانية إلى هذاfn
, ، في وقت واحد.
لذلك:
(reduce fn-to-update-values-in-our-map
initial-value-of-our-map
collection-of-keys)
fn-to-update-values-in-our-map
هو فقط assoc
بيان من فوق ، ملفوفة في وظيفة مجهول:
(fn [map-so-far some-key] (assoc map-so-far some-key (f (map-so-far some-key))))
حتى توصيله إلى reduce
:
(reduce (fn [map-so-far some-key] (assoc map-so-far some-key (f (map-so-far some-key))))
amap
keyseq)
في Clojure هناك اختزال الكتابة مجهول وظائف: #(...)
هو مجهول fn
تتألف من واحد ، %1
لا بد أن الحجة الأولى إلى وظيفة مجهول ، %2
إلى الثاني ، إلخ.لذلك لدينا fn
من فوق يمكن كتابة مكافئ مثل:
#(assoc %1 %2 (f (%1 %2)))
وهذا يعطينا:
(reduce #(assoc %1 %2 (f (%1 %2))) amap keyseq)
نصائح أخرى
(defn doto-map [m ks f & args]
(reduce #(apply update-in %1 [%2] f args) m ks))
والدعوة مثال
user=> (doto-map {:a 1 :b 2 :c 3} [:a :c] + 2)
{:a 3, :b 2, :c 5}
وتأمل أن يساعد هذا.
وفيما يلي يبدو للعمل:
(defn doto-map [ks f amap]
(into amap
(map (fn [[k v]] [k (f v)])
(filter (fn [[k v]] (ks k)) amap))))
user=> (doto-map #{:hello :foo} (fn [k] (.toUpperCase k)) {:hello "World" :try "This" :foo "bar"})
{:hello "WORLD", :try "This", :foo "BAR"}
وربما تكون هناك طريقة أفضل للقيام بذلك. ربما شخص ما يمكن أن تأتي مع لطيفة أونيلينير:)