2012-02-22 11 views
10

clojure में, मैं इस डेटा इकट्ठा करना चाहते हैं:क्लोजर में, तत्वों को कैसे समूहित करें?

(def data [[:morning :pear][:morning :mango][:evening :mango][:evening :pear]]) 
(group-by first data) 
;{:morning [[:morning :pear][:morning :mango]],:evening [[:evening :mango][:evening :pear]]} 

मेरे समस्या यह है कि :evening और :morning बेमानी हो रहा है। इसके बजाय, मैं निम्नलिखित संग्रह बनाने के लिए करना चाहते हैं:

([:morning (:pear :mango)] [:evening (:mango :pear)]) 

मैं के साथ आया था:

(for [[moment moment-fruit-vec] (group-by first data)] [moment (map second moment-fruit-vec)]) 

वहाँ एक और अधिक मुहावरेदार समाधान है?

+1

में चर नाम अपने प्रस्तावित समाधान भ्रामक है। 'फल' के रूप में नष्ट मूल्य वास्तव में पल-फल जोड़ी वैक्टर का अनुक्रम है। –

+0

बहुत बहुत धन्यवाद! प्रश्न – viebel

उत्तर

5

मैं समान समूह समस्याओं में आया हूं। आम तौर पर मैं अंत प्लग विलय-साथ या अपडेट-में कुछ seq प्रसंस्करण कदम में:

(apply merge-with list (map (partial apply hash-map) data)) 

आप किसी मैप मिलता है, लेकिन यह सिर्फ कुंजी-मान जोड़ों का एक seq है:

user> (apply merge-with list (map (partial apply hash-map) data)) 
{:morning (:pear :mango), :evening (:mango :pear)} 
user> (seq *1) 
([:morning (:pear :mango)] [:evening (:mango :pear)]) 

यह समाधान केवल वही मिलता है जो आप चाहते हैं यदि प्रत्येक कुंजी दो बार दिखाई देती है। यह बेहतर हो सकता है:

(reduce (fn [map [x y]] (update-in map [x] #(cons y %))) {} data) 

इनमें से दोनों "अधिक कार्यात्मक" महसूस करते हैं लेकिन थोड़ा कम महसूस करते हैं। अपने समाधान को खारिज करने के लिए बहुत जल्दी मत बनो, यह समझने में आसान और कार्यात्मक है।

+1

अपडेट किया गया है 'के बारे में आप क्या सोचते हैं (मर्ज-साथ (कॉम्प फ्लैटन सूची) लागू करें (नक्शा (आंशिक लागू हैश-मैप) डेटा)) '? – viebel

+1

यह एक अच्छा, संक्षिप्त तय है। मेरा मानना ​​है कि 'flatten' ** ओ (एन) ** है, इसलिए यह कुछ डेटासेट में इसे बार-बार लागू करने में अच्छी तरह से काम नहीं कर सकता है। –

+1

आप सही हैं। मुझे एक बेहतर समाधान मिला, मेरा जवाब देखें। बीटीडब्लू क्या कोई अंतर्निहित फ़ंक्शन है जो 'agg' जैसा ही करता है? – viebel

4

भी group-by खारिज करने के लिए जल्दी मत बनो करो, यह इच्छित कुंजी के द्वारा अपने डेटा एकत्रित किया गया है और यह डेटा नहीं बदला है। पल-फलों के जोड़े के अनुक्रम की अपेक्षा रखने वाला कोई भी अन्य कार्य group-by द्वारा लौटाए गए मानचित्र में देखे गए किसी भी मूल्य को स्वीकार करेगा।

सारांश की गणना करने के संदर्भ में मेरी झुकाव merge-with तक पहुंचने के लिए थी, लेकिन इसके लिए मुझे इनपुट डेटा को नक्शे के अनुक्रम में बदलना था और आवश्यक कुंजी और खाली-वैक्टर के साथ "आधार-मानचित्र" बनाना था ।

(let [i-maps (for [[moment fruit] data] {moment fruit}) 
     base-map (into {} 
        (for [key (into #{} (map first data))] 
        [key []]))] 
     (apply merge-with conj base-map i-maps)) 

{:morning [:pear :mango], :evening [:mango :pear]} 
2

@mike t के जवाब पर मनन करने, मैं ले कर आए हैं:

(defn agg[x y] (if (coll? x) (cons y x) (list y x))) 
(apply merge-with agg (map (partial apply hash-map) data)) 

यह समाधान भी काम करता है जब कुंजी data पर दो बार से अधिक दिखाई देते हैं:

(apply merge-with agg (map (partial apply hash-map) 
    [[:morning :pear][:morning :mango][:evening :mango] [:evening :pear] [:evening :kiwi]])) 
;{:morning (:mango :pear), :evening (:kiwi :pear :mango)} 
संबंधित मुद्दे