سؤال

أريد تحويل خريطة واحدة من القيم إلى خريطة أخرى مع نفس المفاتيح ولكن مع وظيفة مطبقة على القيم. أعتقد أن هناك وظيفة للقيام بذلك في API Clojure، لكنني لم أتمكن من العثور عليه.

إليك تطبيق مثال لما أبحث عنه

(defn map-function-on-map-vals [m f]
  (reduce (fn [altered-map [k v]] (assoc altered-map k (f v))) {} m))
(println (map-function-on-map-vals {:a "test" :b "testing"} #(.toUpperCase %)))
{:b TESTING, :a TEST}

هل يعرف أي شخص ما إذا map-function-on-map-vals موجود مسبقا؟ أعتقد أنه فعلت (ربما مع اسم أجمل أيضا).

هل كانت مفيدة؟

المحلول

أعجبني reduce نسخة جيدة فقط. أعتقد أنه من الناحية الاصطلاحية. إليك نسخة باستخدام الفهم القائمة على أي حال.

(defn foo [m f]
  (into {} (for [[k v] m] [k (f v)])))

نصائح أخرى

يمكنك استعمال ال clojure.algo.generic.functor/fmap:

user=> (use '[clojure.algo.generic.functor :only (fmap)])
nil
user=> (fmap inc {:a 1 :b 3 :c 5})
{:a 2, :b 4, :c 6}

فيما يلي طريقة نموذجية إلى حد ما لتحويل الخريطة. zipmap يأخذ قائمة مفاتيح وقائمة القيم و "هل الشيء الصحيح" ينتج خريطة عباءة جديدة. يمكنك أيضا وضع map حول المفاتيح لتغييرها، أو كليهما.

(zipmap (keys data) (map #(do-stuff %) (vals data)))

أو لفه في وظيفتك:

(defn map-function-on-map-vals [m f]
    (zipmap (keys m) (map f (vals m))))

مأخوذة من كتاب Clojure Cook، هناك تقليل KV:

(defn map-kv [m f]
  (reduce-kv #(assoc %1 %2 (f %3)) {} m))

إليك طريقة اصطلاحية إلى حد ما للقيام بذلك:

(defn map-function-on-map-vals [m f]
        (apply merge
               (map (fn [[k v]] {k (f v)})
                    m)))

مثال:

user> (map-function-on-map-vals {1 1, 2 2, 3 3} inc))
{3 4, 2 3, 1 2}

map-map, map-map-keys, ، و map-map-values

أعرف عدم وجود وظيفة موجودة في عباءة لهذا الغرض، ولكن هنا تنفيذ هذه الوظيفة map-map-values أنك حر في نسخ. لأنه يأتي مع وظيفتين وثيق الصلة، map-map و map-map-keys, ، والتي هي أيضا مفقودة من المكتبة القياسية:

(defn map-map
    "Returns a new map with each key-value pair in `m` transformed by `f`. `f` takes the arguments `[key value]` and should return a value castable to a map entry, such as `{transformed-key transformed-value}`."
    [f m]
    (into (empty m) (map #(apply f %) m)) )

(defn map-map-keys [f m]
    (map-map (fn [key value] {(f key) value}) m) )

(defn map-map-values [f m]
    (map-map (fn [key value] {key (f value)}) m) )

الاستعمال

تستطيع الاتصال map-map-values مثله:

(map-map-values str {:a 1 :b 2})
;;           => {:a "1", :b "2"}

والوظائف الأخرى مثل هذا:

(map-map-keys str {:a 1 :b 2})
;;         => {":a" 1, ":b" 2}
(map-map (fn [k v] {v k}) {:a 1 :b 2})
;;    => {1 :a, 2 :b}

تطبيقات بديلة

إذا كنت تريد فقط map-map-keys أو map-map-values, ، دون أكثر عمومية map-map وظيفة، يمكنك استخدام هذه التطبيقات، والتي لا تعتمد على map-map:

(defn map-map-keys [f m]
    (into (empty m)
        (for [[key value] m]
            {(f key) value} )))

(defn map-map-values [f m]
    (into (empty m)
        (for [[key value] m]
            {key (f value)} )))

أيضا، وهنا تنفيذ بديل لل map-map هذا يعتمد على clojure.walk/walk بدلاً من into, ، إذا كنت تفضل هذا الصياغة:

(defn map-map [f m]
    (clojure.walk/walk #(apply f %) identity m) )

إصدارات Parellel - pmap-map, ، إلخ.

هناك أيضا إصدارات متوازية من هذه الوظائف إذا كنت في حاجة إليها. انهم ببساطة استخدام pmap بدلاً من map.

(defn pmap-map [f m]
    (into (empty m) (pmap #(apply f %) m)) )
(defn pmap-map-keys [f m]
    (pmap-map (fn [key value] {(f key) value}) m) )
(defn pmap-map-values [f m]
    (pmap-map (fn [key value] {key (f value)}) m) )

أنا عباءة N00B، لذلك قد يكون هناك حلول أكثر أناقة. هنا لي:

(def example {:a 1 :b 2 :c 3 :d 4})
(def func #(* % %))

(prn example)

(defn remap [m f]
  (apply hash-map (mapcat #(list % (f (% m))) (keys m))))

(prn (remap example func))

يوفر Anon Func قائمة من كل مفتاح وقيمتها F'ED. يعمل MAPCAT هذه الوظيفة على تسلسل مفاتيح الخريطة وتسلسل كامل يعمل في قائمة واحدة كبيرة. "تطبيق خريطة التجزئة" يخلق خريطة جديدة من هذا التسلسل. قد تبدو (٪ م) تبدو غريبة قليلا، فهي عباءة عنية لتطبيق مفتاح على الخريطة للبحث عن القيمة المرتبطة بها.

قراءة أكثر موصى بها للغاية: البعد الغش ورقة .

أعجبني reduce الإصدار. مع وجود تباين بسيط للغاية، يمكن أيضا الاحتفاظ بنوع هياكل السجلات:

(defn map-function-on-map-vals [m f]
  (reduce (fn [altered-map [k v]] (assoc altered-map k (f v))) m m))

ال {} تم استبداله ب m. وبعد مع هذا التغيير، لا تزال السجلات سجلات:

(defrecord Person [firstname lastname])

(def p (map->Person {}))
(class p) '=> Person

(class (map-function-on-map-vals p
  (fn [v] (str v)))) '=> Person

من خلال بدء {}, ، سجل السجل السجل, ، أيهما قد يرغب في الاحتفاظ، إذا كنت ترغب في إمكانات القياسية (تمثيل الذاكرة المدمجة على سبيل المثال).

(defn map-vals
  "Map f over every value of m.
   Returns a map with the same keys as m, where each of its values is now the result of applying f to them one by one.
   f is a function of one arg, which will be called which each value of m, and should return the new value.
   Faster then map-vals-transient on small maps (8 elements and under)"
  [f m]
  (reduce-kv (fn [m k v]
               (assoc m k (f v)))
             {} m))

(defn map-vals-transient
  "Map f over every value of m.
   Returns a map with the same keys as m, where each of its values is now the result of applying f to them one by one.
   f is a function of one arg, which will be called which each value of m, and should return the new value.
   Faster then map-vals on big maps (9 elements or more)"
  [f m]
  (persistent! (reduce-kv (fn [m k v]
                            (assoc! m k (f v)))
                          (transient {}) m)))
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top