2012-09-30 25 views
5

में सबसे अधिक लगातार वस्तुओं को खोजने के लिए इडियोमैटिक क्लोजर तरीका, वस्तुओं की एक अनुक्रम को देखते हुए मैं आवृत्ति के अवरोही क्रम में, सबसे अधिक लगातार वस्तुओं को ढूंढना चाहता हूं। उदाहरण के लिए मैं पारित करने के लिए इस इकाई परीक्षण करना चाहते हैं:एक सीक

(fact "can find 2 most common items in a sequence" 
     (most-frequent-n 2 ["a" "bb" "a" "x" "bb" "ccc" "dddd" "dddd" "bb" "dddd" "bb"]) 
     => 
     '("bb" "dddd")) 

मैं काफी Clojure और अभी भी मानक पुस्तकालय के साथ पकड़ करने के लिए प्राप्त करने की कोशिश नया हूँ। यहां मैं यह हुआ हूं:

(defn- sort-by-val [s]  (sort-by val s)) 
(defn- first-elements [pairs] (map #(get % 0) pairs)) 

(defn most-frequent-n [n items] 
    "return the most common n items, e.g. 
    (most-frequent-n 2 [:a :b :a :d :x :b :c :d :d :b :d :b]) => 
     => (:d :b)" 
    (take n (-> 
      items    ; [:a :b :a :d :x :b :c :d :d :b :d :b] 
      frequencies   ; {:a 2, :b 4, :d 4, :x 1, :c 1} 
      seq     ; ([:a 2] [:b 4] [:d 4] [:x 1] [:c 1]) 
      sort-by-val   ; ([:x 1] [:c 1] [:a 2] [:b 4] [:d 4]) 
      reverse    ; ([:d 4] [:b 4] [:a 2] [:c 1] [:x 1]) 
      first-elements))) ; (:d :b :a :c :x) 

हालांकि यह काफी आम ऑपरेशन करने के लिए कार्यों की एक जटिल श्रृंखला की तरह लगता है। क्या ऐसा करने के लिए एक और अधिक सुरुचिपूर्ण या अधिक मूर्खतापूर्ण (या अधिक कुशल) तरीका है?

उत्तर

8

जैसा कि आपने पाया है, आमतौर पर आप आवृत्ति-क्रमबद्ध सूची प्राप्त करने के लिए क्रमबद्ध और आवृत्तियों के संयोजन का उपयोग करेंगे।

(sort-by val (frequencies ["a" "bb" "a" "x" "bb" "ccc" "dddd" "dddd" "bb" "dddd" "bb"])) 
=> (["x" 1] ["ccc" 1] ["a" 2] ["dddd" 3] ["bb" 4]) 

फिर आप निम्नतम/उच्चतम आवृत्ति वस्तुओं को प्राप्त करने के लिए इसे आसानी से कुशलतापूर्वक उपयोग कर सकते हैं। शायद की तरह कुछ:

(defn most-frequent-n [n items] 
    (->> items 
    frequencies 
    (sort-by val) 
    reverse 
    (take n) 
    (map first))) 

कौन सा फिर से सुंदर अपने समाधान (से है कि आप ->> मैक्रो के चतुर उपयोग के साथ सहायक कार्यों की जरूरत नहीं है के अलावा) के समान है।

तो कुल मिलाकर मुझे लगता है कि आपका समाधान बहुत अच्छा है। कार्यों की श्रृंखला के बारे में चिंता न करें - यह वास्तव में एक जटिल अवधारणा के लिए वास्तव में एक बहुत छोटा समाधान है। सी #/जावा में एक ही चीज़ को कोड करने का प्रयास करें और आप देखेंगे कि मेरा क्या मतलब है ......

+1

धन्यवाद मिकरा, आपका समाधान एक अच्छा सुधार है। (1) मैं देखता हूं कि सहायक कार्यों की आवश्यकता से बचने के लिए तीर मैक्रोज़ का सही तरीके से उपयोग कैसे करें। (2) 'सॉर्ट-बाय' पहले 'seq' करने की आवश्यकता के बिना' आवृत्तियों 'के परिणाम पर सीधे काम कर सकता है। (3) मानक पुस्तकालय में 'पहला' फ़ंक्शन है इसलिए मुझे अपना खुद का निर्माण करने की आवश्यकता नहीं है। (4) 'मानचित्र' से पहले 'टेक' करना संभवतः अधिक कुशल है। –

+5

'(रिवर्स (सॉर्ट-बाय एफ कॉल)) 'वास्तविक कारण के लिए डरावना महंगा है - इसके बजाए' (सॉर्ट-बाय (कॉम्प-एफ) कॉल) '। साथ ही, मैं इस बारे में लगातार रहूंगा कि आप 'प्रथम' और 'दूसरा' या 'कुंजी' और' वैल 'का उपयोग करते हैं, क्योंकि वे मानचित्र प्रविष्टियों के बराबर हैं। – amalloy