4clojure #63 Group a Sequence
4clojure #63 Group a Sequence
関数fとシーケンスsを与えてマップを返す関数を作る。 キーはsの各項にfをapplyした値です。 各キーに対応する値はsの順番で連続する項の続くベクターです。
※ group-by
は使用禁止。
(= (__ #(> % 5) [1 3 6 8]) {false [1 3], true [6 8]}) (= (__ #(apply / %) [[1 2] [2 4] [4 6] [3 6]]) {1/2 [[1 2] [2 4] [3 6]], 2/3 [[4 6]]}) (= (__ count [[1] [1 2] [3] [1 2 3] [2 3]]) {1 [[1] [3]], 2 [[1 2] [2 3]], 3 [[1 2 3]]})
まず、map
で各seq
にf
を作用させて、結果と元の値とのリストを作り
ソートして結果ごとに小グループを作る。
((fn my-gr [f coll] (partition-by first (sort-by first (map #(list (f %) %) coll)))) #(> % 5) [1 3 6 8]) ;=> (((false 1) (false 3)) ((true 6) (true 8)))
あとは、求める形式に表現を変更するだけ。
(into {} (map #(hash-map (first (first %)) (into [] (map second %))) '(((false 1) (false 3)) ((true 6) (true 8))))) ; => {false [1 3], true [6 8]}
group-by
の定義には劣るけれども自力でとけたのでよかったです。
((fn my-gr [f coll] (into {} (map #(hash-map (first (first %)) (into [] (map second %))) (partition-by first (sort-by first (map #(list (f %) %) coll)))))) #(> % 5) [1 3 6 8])
参考 group-by
の定義
(defn group-by "Returns a map of the elements of coll keyed by the result of f on each element. The value at each key will be a vector of the corresponding elements, in the order they appeared in coll." {:added "1.2" :static true} [f coll] (persistent! (reduce (fn [ret x] (let [k (f x)] (assoc! ret k (conj (get ret k []) x)))) (transient {}) coll)))