《例示は理解の試金石》
Clojureではいろんなデータを「シーケンス」として扱います(Clojure - sequences)。だからシーケンスを操作する関数をいろいろ使うことになりますが、ちょっと複雑な操作をしようとすると基本的な関数だけでは足りなくて自分で処理を書くことになります。ところがあとで標準ライブラリをよく読んでみると「この関数使えばもっと簡単に処理を書けたんじゃん! 知らなかったばっかりに(ぐぬぬ」となることもあります。
拡張ライブラリのclojure.contrib.seqはちょっと便利なシーケンス関数をまとめたものですが、ドキュメントをちょっと読んだだけだと使いかたが分かりにくい。そこで各関数の使用例をまとめてみました。これでライブラリにある関数を再発明しないで済むはずだ!
gist: 780422 - GitHub
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns intro-seq.core | |
(:use [clojure.contrib seq])) | |
;; Clojure初心者向けに覚えておくと便利なシーケンス操作関数の使用例を列挙する | |
;; 1.2でclojure.coreに移動し、廃止予定(DEPRECATED.)になってるのもある | |
;; 全部で18個(DEPRECATEDは8個) | |
;; 使用頻度高そう系(4個) | |
;; たまに使うかも系(3個) | |
;; パズルを解くときに使うかも系(3個) | |
;; シーケンスをグループ分け系(4個) | |
;; 自己参照する遅延シーケンスをつくる系(2個) | |
;; とりあえず知っとけばいいんじゃね?系(2個) | |
;; 使用頻度高そう系(4個) | |
;find-first | |
;シーケンスの中から条件に合う最初の要素を返す | |
(find-first #(> % 3) [1 2 3 4 5]) | |
;=> 4 | |
(find-first #(Character/isLowerCase %) "Clojure") | |
;\l | |
;includes? | |
;シーケンス内に要素あるか調べる | |
(includes? [1 2 3 4 5] 4) | |
;true | |
(includes? [1 2 3 4 5] 10) | |
;false | |
(includes? "clojure" \c) | |
;true | |
(includes? "clojure" \x) | |
;false | |
;flatten | |
;DEPRECATED. Prefer clojure.core version. | |
;階層構造のあるシーケンスを均す | |
(flatten '((1 2 3) (4 5 6))) | |
;=> (1 2 3 4 5 6) | |
; positions | |
; 条件が真になる要素の位置のシーケンスを返す | |
(positions #(> 4 %) '(1 2 3 4 5)) | |
;(0 1 2) | |
(positions #(= \c %) "clojure is cool") | |
;(0 11) | |
;; たまに使うかも系(3個) | |
;indexed | |
; シーケンスの各要素をインデックス付きのベクタに変える | |
; clojure.core/map-indexedも便利 | |
; C言語などのfor文のような感じで使える | |
(indexed '(:a :b :c)) | |
;([0 :a] [1 :b] [2 :c]) | |
(indexed "clojure") | |
;([0 \c] [1 \l] [2 \o] [3 \j] [4 \u] [5 \r] [6 \e]) | |
;frequencies | |
;DEPRECATED. Prefer clojure.core version. | |
;シーケンスの要素の出現回数を数える | |
;要素をkey,出現回数をvalueにしたマップを返す | |
(frequencies [1 1 2 3 5 8]) | |
;{8 1, 5 1, 3 1, 2 1, 1 2} | |
(frequencies "clojure is cool") | |
;{\space 2, \c 2, \e 1, \i 1, \j 1, \l 2, \o 3, \r 1, \s 1, \u 1} | |
;reductions | |
;DEPRECATED. Prefer clojure.core version. | |
; シーケンスの先頭から各要素までreduceした結果を返す | |
; rec-seqを使って実装されている | |
(reductions (fn [r x] (+ r x)) [1 2 3 4 5]) | |
;(1 3 6 10 15) | |
(reductions (fn [r x] (* r x)) [1 2 3 4 5]) | |
;(1 2 6 24 120) | |
;; パズルを解くときに使うかも系(3個) | |
;; パズルを解きたい時にはc.c.combinatoricsも見てみると楽になるかも | |
;rotations | |
;シーケンスの最初の要素を最後に持って行き、循環させたものを順番にシーケンス化 | |
(rotations [1 2 3 4]) | |
;((1 2 3 4) (2 3 4 1) (3 4 1 2) (4 1 2 3)) | |
;rand-nth(rand-elt) | |
;DEPRECATED. Prefer clojure.core/rand-nth. | |
; ランダム選択 | |
(rand-elt [1 2 3 4 5]) | |
(rand-nth [1 2 3 4 5]) | |
;4 | |
(rand-nth [1 2 3 4 5]) | |
;2 | |
(rand-nth "Clojure") | |
;\e | |
(rand-nth "Clojure") | |
;\o | |
(rand-nth "Clojure") | |
;\o | |
(rand-nth "Clojure") | |
;\u | |
(rand-nth "Clojure") | |
;\o | |
;shuffle | |
;DEPRECATED. Prefer clojure.core version. | |
;ランダムシャッフル | |
(shuffle [1 2 3 4 5]) | |
;(3 1 5 4 2) | |
(shuffle [1 2 3 4 5]) | |
;(3 4 5 2 1) | |
(shuffle [1 2 3 4 5]) | |
;(1 4 3 5 2) | |
(shuffle [1 2 3 4 5]) | |
;(4 3 2 1 5) | |
;; シーケンスをグループ分け系(4個) | |
;group-by | |
;DEPRECATED. Prefer clojure.core version. | |
;シーケンスの要素に指定された関数を適用し、その結果が同じものをグループ化する | |
;関数の値をkey、vectorでグループ化したものをvalueにしたMapを返す | |
(group-by #(* 2 %) [1 2 3 4 5]) | |
;{2 [1], 4 [2], 6 [3], 8 [4], 10 [5]} | |
(group-by odd? (range 10)) | |
;{false [0 2 4 6 8], true [1 3 5 7 9]} | |
;partition-all | |
;DEPRECATED. Prefer clojure.core version. | |
; シーケンス要素を指定した個数ごとにまとめる | |
(partition-all 2 '(1 2 3 4 5 6 7 8)) | |
;((1 2) (3 4) (5 6) (7 8)) | |
(partition-all 3 '(1 2 3 4 5 6 7 8)) | |
;((1 2 3) (4 5 6) (7 8)) | |
(partition-all 1 2 '(1 2 3 4 5 6 7 8)) | |
;((1) (3) (5) (7)) | |
;partition-by | |
;DEPRECATED. Prefer clojure.core version. | |
; シーケンスを条件ごとに切り分ける | |
; シーケンス要素に関数を摘要し、同じ結果が返る連続する要素をグループ化 | |
(partition-by #(> 3 %) '(1 2 3 4 5)) | |
;((1 2) (3 4 5)) | |
(partition-by odd? (range 10)) | |
;((0) (1) (2) (3) (4) (5) (6) (7) (8) (9)) | |
;separate | |
; シーケンスをfilterして取得したものと、それ以外を両方取得 | |
; 奇数と偶数に分けてみる | |
(separate odd? (range 10)) | |
;[(1 3 5 7 9) (0 2 4 6 8)] | |
;; 自己参照する遅延シーケンスをつくる系(2個) | |
;rec-seq | |
; 自己参照するシーケンスを作る | |
(take 10 (rec-seq self (lazy-cat (range 3) self))) | |
;(0 1 2 0 1 2 0 1 2 0) | |
;rec-cat | |
; 自己参照するシーケンスをconcatする | |
(take 10 (rec-cat fibs [1 1] (map + fibs (rest fibs)))) | |
;(1 1 2 3 5 8 13 21 34) | |
;http://clj-me.blogspot.com/2009/01/recursive-seqs.html | |
;; とりあえず知っとけばいいんじゃね?系(2個) | |
;seq-on | |
;任意の型を(seq ~)でシーケンスに変換できるように定義できるマルチメソッド | |
;fill-queue | |
; スレッド間で通信できる?(よく分からない) | |
; ↓でfill-queueの使用例が見れる | |
;The Infolace Story: Simple webhooks with Clojure and Ring | |
;http://infolace.blogspot.com/2009/08/simple-webhooks-with-clojure-and-ring.html |
rec-seq、rec-catはイマイチ用途が分かってません。
最後のfill-queueだけ毛色が違いすぎます(入れる名前空間間違ってない?)。これは別に使用例を書く予定。
c.c.seqの関数はclojure.coreに移動予定のも多いです。coreに入っちゃうと他とごっちゃになって分かりにくくなると思うので今のうちに試してみては?
【参考リンク】
Clojure - cheatsheet
このチートシートを印刷しておくのも便利。
追記(2011-12-25)
fill-queueの使用例も書きました
fill-queueでお手軽非同期処理 : サルノオボエガキ