Clojure:كيف يمكنني التقدم بطلب وظيفة إلى مجموعة فرعية من الإدخالات في تجزئة الخريطة ؟

StackOverflow https://stackoverflow.com/questions/1638854

  •  08-07-2019
  •  | 
  •  

سؤال

أنا لا 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"}

وربما تكون هناك طريقة أفضل للقيام بذلك. ربما شخص ما يمكن أن تأتي مع لطيفة أونيلينير:)

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top