क्लोजर में एक मानचित्र के मूल्यों पर एक फ़ंक्शन का मानचित्रण


138

मैं मानों के एक मानचित्र को उसी कुंजी के साथ दूसरे मानचित्र में बदलना चाहता हूं, लेकिन मानों पर लागू फ़ंक्शन के साथ। मुझे लगता है कि क्लोजर एपी में ऐसा करने के लिए एक समारोह था, लेकिन मैं इसे खोजने में असमर्थ रहा हूं।

यहाँ एक उदाहरण कार्यान्वयन है जो मैं देख रहा हूँ

(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पहले से मौजूद है? मुझे लगता है कि यह किया (शायद एक अच्छे नाम के साथ भी)।

जवाबों:


153

मुझे आपका reduceसंस्करण ठीक लगा। मुझे लगता है कि यह मुहावरेदार है। यहाँ वैसे भी सूची का उपयोग कर एक संस्करण है।

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

1
मुझे यह संस्करण पसंद है क्योंकि यह सुपर छोटा और स्पष्ट है यदि आप सभी कार्यों को समझते हैं और इस तरह इसका उपयोग करते हैं। और अगर तुम उन्हें सीखने के लिए एक बहाना नहीं है!
रुनवुल्ट

मैं सहमत हूँ। मैं समारोह में नहीं जानता था, लेकिन यह यहाँ इसका उपयोग करने के लिए एकदम सही समझ में आता है।
थॉमस

अरे यार तुम में नहीं देखा था? पार्टी में आप भी शामिल हो। मुझे लगता है कि मुझे मिलने वाले हर फंक्शन से नरक का दुरुपयोग होता है। इतना शक्तिशाली और उपयोगी।
रतवात

3
मुझे यह पसंद है, लेकिन क्या तर्क के आदेश का कोई कारण है (प्रश्न के अलावा)? मैं mapकिसी कारण से [fm] उम्मीद कर रहा था ।
न्हा।

2
मैं दृढ़ता से उपयोग करने की सलाह देता हूं (खाली एम) बल्कि {}। इसलिए यह एक विशेष प्रकार का मानचित्र होता रहेगा।
nickik

96

आप इसका उपयोग कर सकते हैं 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}

मुझे पता है कि यह उत्तर तारीखों को देखने में थोड़ा देर से था, लेकिन मुझे लगता है कि यह हाजिर है।
एडवर्ड्समैट

क्या इसने इसे क्लोजर 1.3.0 में बनाया?
अन्नपूर्णे

13
Generic.function lib एक अलग लाइब्रेरी में चला गया है: org.clojure/algo.generic "0.1.0" उदाहरण को अब पढ़ा जाना चाहिए: (use '[clojure.algo.generic.functor :only (fmap)]) (fmap inc {:a 1 :b 3 :c 5})
ट्रैविस श्नीबर्गर

2
किसी भी विचार कैसे fmapClojureScript में खोजने के लिए ?
sebastibe

37

यहां एक नक्शे को बदलने के लिए एक काफी विशिष्ट तरीका है। 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))))

1
यह मुझे परेशान करता है कि मुझे इसके लिए चाबियों की आपूर्ति करनी है, लेकिन यह भुगतान करने के लिए उच्च कीमत नहीं है। यह निश्चित रूप से मेरे मूल सुझाव की तुलना में बहुत अच्छा लग रहा है।
थॉमस

1
क्या हम गारंटी देते हैं कि कुंजियाँ और वैलियाँ एक ही क्रम में संबंधित मान लौटाती हैं? सॉर्ट किए गए मैप्स और हैश मैप्स दोनों के लिए?
रॉब लचलान

4
Rob: हाँ, कुंजियाँ और मान सभी मानचित्रों के लिए समान क्रम का उपयोग करेंगे - मानचित्र के उपयोग पर seq के समान क्रम। चूंकि हैश, सॉर्ट किए गए, और सरणी मानचित्र सभी अपरिवर्तनीय हैं, इसलिए उस समय में ऑर्डर बदलने का कोई मौका नहीं है।
चॉसर

2
यह मामला प्रतीत होता है, लेकिन क्या यह कहीं भी प्रलेखित है? कम से कम चाबियाँ और घाटी के लिए docstrings यह उल्लेख करने में विफल। अगर मैं काम करने जा रहा हूं तो मैं कुछ आधिकारिक दस्तावेज़ीकरण की ओर इशारा कर सकता हूं, तो मैं इसका उपयोग करना अधिक आरामदायक होगा।
जौनी के। सेबपैन

1
@ जेसन हाँ, उन्होंने इसे संस्करण 1.6 में दस्तावेज़ में जोड़ा है मुझे लगता है। dev.clojure.org/jira/browse/CLJ-1302
Jouni K. Seppänen

23

क्लोजर कुकबुक से लिया गया, कम-केवी है:

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

8

यहाँ यह करने के लिए एक बहुत ही मुहावरेदार तरीका है:

(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}

2
यदि यह स्पष्ट नहीं है: aon फंक्शन k और v की कुंजी और मान को नष्ट कर देता है और फिर हैश-मैप मैपिंग k to (fv) देता है
सिद्धार्थ रेड्डी

6

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-valuesmap-mapmap-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) )

पैरेलल संस्करण - 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) )

1
इसके अलावा प्रिज्मीटिक्स मैप-वैल फ़ंक्शन की जांच करें। यह तेजी से ग्राहकों का उपयोग कर रहा है github.com/Prismatic/plolding/blob/…
ClojureMostly

2

मैं क्लोजर 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))

आयन फंक प्रत्येक कुंजी और उसके f'ed मान से थोड़ी 2-सूची बनाता है। Mapcat इस फ़ंक्शन को मानचित्र की कुंजियों के अनुक्रम पर चलाता है और संपूर्ण कार्यों को एक बड़ी सूची में सम्मिलित करता है। "हैश-मैप लागू करें" उस क्रम से एक नया नक्शा बनाता है। (% M) थोड़ा अजीब लग सकता है, यह संबद्ध मूल्य को देखने के लिए मानचित्र की कुंजी लगाने के लिए मुहावरेदार क्लोजर है।

सबसे अधिक अनुशंसित पढ़ने: क्लोजर चीट शीट


जैसा कि आपने अपने उदाहरण में किया है, मैं गर्त अनुक्रमों के बारे में सोचा। मैं भी पहले की तरह काम भी बहुत कुछ मेरे अपने :) से आप के नाम की तरह
थॉमस

क्लॉज्योर में, कीवर्ड ऐसे फ़ंक्शंस होते हैं जो अपने आप को उसी क्रम में देखते हैं, जो उनके पास जाता है। इसीलिए (: खोजशब्द का नक्शा) काम करता है। लेकिन कुंजी को कीवर्ड के रूप में देखने के लिए फ़ंक्शन के रूप में उपयोग करना महत्वपूर्ण नहीं है यदि कुंजी एक कीवर्ड नहीं है। तो आप (m%) से ऊपर (% m) को बदलना चाह सकते हैं, जो बिना किसी परवाह के काम करेगा।
सिद्धार्थ रेड्डी

ऊप्स! टिप के लिए धन्यवाद, सिद्धार्थ!
कार्ल स्मोत्रिकज

2
(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)))

1

मुझे आपका 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

के साथ शुरू करके {}, रिकॉर्ड अपनी रिकॉर्डता खो देता है , जिसे आप रिकॉर्ड क्षमताओं (उदाहरण के लिए कॉम्पैक्ट मेमोरी प्रतिनिधित्व) को बनाए रखना चाहते हैं।


0

मैं सोच रहा हूं कि किसी ने अभी तक दर्शक पुस्तकालय का उल्लेख क्यों नहीं किया है। यह इस तरह के परिवर्तन को कोड को आसान बनाने के लिए लिखा गया है (और, और भी महत्वपूर्ण, लिखित कोड को समझना आसान है), जबकि अभी भी बहुत अच्छा प्रदर्शन किया जा रहा है:

(require '[com.rpl.specter :as specter])

(defn map-vals [m f]
  (specter/transform
   [specter/ALL specter/LAST]
   f m))

(map-vals {:a "test" :b "testing"}
          #(.toUpperCase %))

शुद्ध क्लोजर में इस तरह के एक फ़ंक्शन को लिखना सरल है, लेकिन विभिन्न डेटा संरचनाओं से बना उच्च नेस्टेड कोड पर जाने पर कोड बहुत पेचीदा हो जाता है। और यह वह जगह है जहाँ दर्शक आता है।

मैं देखने की सलाह देते इस प्रकरण जो प्रेरणा के पीछे और के विवरण बताते हैं Clojure टीवी पर काली छाया


0

क्लोजर 1.7 ( 30 जून, 2015 को जारी ) इसके साथ एक सुरुचिपूर्ण समाधान प्रदान करता है update:

(defn map-function-on-map-vals [m f]
    (map #(update % 1 f) m))

(map-function-on-map-vals {:a "test" :b "testing"} #(.toUpperCase %))
;; => ([:a "TEST"] [:b "TESTING"])
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.