2012-09-30 35 views
5

Cho một chuỗi các mục tôi muốn tìm các mục thường xuyên nhất, theo thứ tự tần số giảm dần. Vì vậy, ví dụ tôi muốn thử nghiệm đơn vị này vượt qua:Cách Clojure thành ngữ để tìm các mục thường xuyên nhất trong seq

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

Tôi khá mới đối với Clojure và vẫn cố gắng nắm bắt thư viện chuẩn. Đây là những gì tôi đã đưa ra:

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

Tuy nhiên điều này có vẻ như một chuỗi phức tạp các chức năng để thực hiện một hoạt động khá phổ biến. Có cách nào thanh lịch hơn hoặc thành ngữ hơn (hoặc hiệu quả hơn) để thực hiện việc này không?

Trả lời

8

Như bạn đã khám phá, thông thường bạn sẽ sử dụng kết hợp sắp xếp theo tần số và tần suất để có danh sách được sắp xếp theo tần suất.

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

Sau đó, bạn có thể thao tác khá dễ dàng để nhận các mục tần số thấp nhất/cao nhất. Có lẽ một cái gì đó như:

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

Điều này lại khá giống với giải pháp của bạn (ngoài việc bạn không cần chức năng trợ giúp với việc sử dụng thông minh macro ->>).

Vì vậy, tôi nghĩ giải pháp của bạn khá tốt. Đừng lo lắng về chuỗi chức năng - nó thực sự là một giải pháp rất ngắn cho khái niệm logic khá phức tạp. Hãy thử mã hóa cùng một điều trong C#/Java và bạn sẽ thấy những gì tôi có nghĩa là ......

+1

Cảm ơn Mikera, giải pháp của bạn là một cải tiến tốt đẹp. (1) Tôi thấy cách sử dụng các macro mũi tên đúng cách để tránh các chức năng trợ giúp. (2) 'sort-by' có thể làm việc trực tiếp trên kết quả của' frequency' mà không cần phải thực hiện 'seq' trước. (3) Có một hàm 'đầu tiên' trong thư viện chuẩn nên tôi không cần phải tạo của riêng mình. (4) Thực hiện 'take' trước' map' có lẽ hiệu quả hơn. –

+5

'(đảo ngược (sắp xếp theo f coll))' là khủng khiếp đắt tiền không có lý do thực sự - thích thay vì '(sắp xếp-by (comp - f) coll)'. Ngoài ra, tôi muốn nhất quán về việc bạn sử dụng 'first' và' second' hoặc 'key' và' val', vì chúng tương đương với các mục nhập bản đồ. – amalloy

Các vấn đề liên quan