Skip to content

Instantly share code, notes, and snippets.

@syou6162
Created September 6, 2012 00:24
Show Gist options
  • Save syou6162/3648601 to your computer and use it in GitHub Desktop.
Save syou6162/3648601 to your computer and use it in GitHub Desktop.
Clojureのsequence関係のユーティリティ関数のまとめ

sequence関係のユーティリティ関数で自分がよく知らないものをまとめておく。

map-indexed

昔はindexedっていうそのまんまな関数があったけど、1.3くらいからなくなっていた。今はmap-indexedっていう関数を使う。よく使うのはこんな感じの使い方。

(map-indexed #(vector %1 %2) ["a" "b" "c" "d" "e"])
; ([0 "a"] [1 "b"] [2 "c"] [3 "d"] [4 "e"])

reductions

reduceしていくときの中間値みたいなのも戻り値の要素に加えておいてくれる。Rでいうところにcumsumっぽいことが簡単にできて便利。reduce likeな関数なので初期値ももちろん取れる。

(reductions + [1 2 3]) ; (1 3 6)

zipmap

intoも似たようなことしなかったっけ...と思って違いを押さえる。intoはvectorをつなげていく。zipmapは最初のvectorをkeyにして二つ目をvalueにしたmapを返す。keyが被ってたら後ろのが生き残るらしい。intoとconcatは何が違うねん、、、と思ったけど、concatのほうはlazylistを返すそうなので、lazyなのが欲しいかそうでないかでintoとconcatを使い分けるとよいのかな。

(zipmap [:a :b :c :d :e] [1 2 3 4 5]) ; {:e 5, :d 4, :c 3, :b 2, :a 1}
(zipmap [:a :a :b :b :c] [1 2 3 4 5]) ; {:c 5, :b 4, :a 2}
(into [:a :a :b :b :c] [1 2 3 4 5]) ; [:a :a :b :b :c 1 2 3 4 5]
(concat [:a :a :b :b :c] [1 2 3 4 5]) ; (:a :a :b :b :c 1 2 3 4 5)
(map vector [:a :b :c] [:x :y :z]) ; ([:a :x] [:b :y] [:c :z])

group-by

第二引数に渡したcollectionを第一引数fに渡したに適用した結果で分類してmapで返す。キーは当然ながらfを適用した結果。

(group-by count ["a" "as" "asd" "aa" "asdf" "qwer"]) ; {1 ["a"], 2 ["as" "aa"], 3 ["asd"], 4 ["asdf" "qwer"]}
(group-by odd? (range 10)) ; {false [0 2 4 6 8], true [1 3 5 7 9]}
(group-by :user_id [{:user_id 1 :uri "/"}
		    {:user_id 2 :uri "/foo"}
		    {:user_id 1 :uri "/account"}]) ; {1 [{:user_id 1, :uri "/"} {:user_id 1, :uri "/account"}], 2 [{:user_id 2, :uri "/foo"}]}

keep

exampleを見たら「それfilterと何が違うん...?」って感じだったけど、keepのほうはtrue falseでfilteringするのではなくnilかどうかでやる関数らしい。ちなみに似た関数にkeep-indexedというのがあって、これは無名関数のほうにindexも使えるようにした感じのものらしい。

(keep #(if (odd? %) %) (range 10)) ; (1 3 5 7 9)
(filter #(if (odd? %) %) (range 10)) ; (1 3 5 7 9)

(keep-indexed #(if (odd? %1) %2) (range 0 10)) ; (1 3 5 7 9)
(keep-indexed (fn [idx v] (if (pos? v) idx)) [-9 0 29 -7 45 3 -8]) ; (2 4 5)

split-at

指定した位置でcollectionをぶったぎる。split-withだと指定した条件を初めて満たすところでぶったぎる。take nとdrop nの組み合わせみたいなもの。

(split-at 2 [1 2 3 4 5]) ; [(1 2) (3 4 5)]
(split-with (partial >= 3) [1 2 3 4 5]) 

iterate

いかにもclojureらしい関数。無限リストを生み出すのだが、関数fと初期値xに関してx、(f x)、(f (f x))、(f (f (f x)))...というようなsequenceを作る。使うときにはtakeとかと合わせて、という感じかな。

(take 3 (iterate inc 0)) ; (0 1 2)

mapcat

複数のcollectionを引数に取り、それぞれをmapした結果を連結する。下のmapしてapply concatと等価、だと思う。

(mapcat reverse [[3 2 1 0] [6 5 4] [9 8 7]]) ; (0 1 2 3 4 5 6 7 8 9)
(apply concat (map reverse [[3 2 1 0] [6 5 4] [9 8 7]])) ; (0 1 2 3 4 5 6 7 8 9)

interleave

2つ、またはそれ以上のsequenceを受け取り、それらの要素を交互に持つようなlazy listを返す。これは例を見ればすぐ分かる。

(interleave '[1 3 5] '[2 4 6]) ; (1 2 3 4 5 6)
(interleave '[1 4 7] '[2 5 8] '[3 6 9]) ; (1 2 3 4 5 6 7 8 9)

interpose

リストの間に一個置きに何か要素を差し挟む関数。my-stringsの例は別途他の関数があるのでそちらを使えばいいが、まぁ例ということで。

(interpose 3 '[1 1 1 1]) ; (1 3 1 3 1 3 1)

(def my-strings ["one" "two" "three"])
(interpose ", " my-strings) ; ("one" ", " "two" ", " "three")
(apply str (interpose ", " my-strings)) "one, two, three"
@kohyama
Copy link

kohyama commented Oct 13, 2016

わかりやすいです.

into の使い所について補足させてください.

into は第一引数のコレクションに, 第二引数のシーケンスの要素全てを, 元のコレクションにとって自然な形で追加 (conj) してくれる関数です.
コレクションがリストやベクタだとあまりありがたみ分かりませんが, ハッシュマップや集合では大変ありがたいです.

(into %1 %2) は,
(reduce conj %1 %2) つまり %1%2 の要素を順に conj したものと同等, さらに噛み砕くと
...(conj (conj %1 %2の最初の要素) %2の二番目の要素)... と同等です.

(into '(:a :b) [:c :b :d])
(reduce conj '(:a :b) [:c :b :d])
(conj (conj (conj '(:a :b) :c) :b) :d)
; => (:d :b :c :a :b)

(into [:a :b] [:c :b :d])
(reduce conj [:a :b] [:c :b :d])
(conj (conj (conj [:a :b] :c) :b) :d)
; => [:a :b :c :b :d]

(into #{:a :b} [:c :b :d])
(reduce conj #{:a :b} [:c :b :d])
(conj (conj (conj #{:a :b} :c) :b) :d)
; => #{:a :b :c :d} (順不同)

(into {:a 1 :b 2} [[:c 3] [:b 4] [:d 5]])
(reduce conj {:a 1 :b 2} [[:c 3] [:b 4] [:d 5]])
(conj (conj (conj {:a 1 :b 2} [:c 3]) [:b 4]) [:d 5])
; => {:a 1 :b 4 :c 3 :d 5} (順不同)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment