Ruby 1.9.3 リファレンスマニュアル > ライブラリ一覧 > 組み込みライブラリ > Enumerableモジュール > chunk
chunk {|elt| ... } -> Enumerator
[permalink][rdoc]chunk(initial_state) {|elt, state| ... } -> Enumerator
要素を前から順にブロックで評価し、その結果によって 要素をチャンクに分けた(グループ化した)要素を持つ Enumerator を返します。
ブロックの評価値が同じ値が続くものを一つのチャンクとして 取り扱います。すなわち、ブロックの評価値が一つ前と 異なる所でチャンクが区切られます。
返り値の Enumerator は各チャンクのブロック評価値と 各チャンクの要素を持つ配列のペアを各要素とします。 そのため、eachだと以下のようになります。
enum.chunk {|elt| key }.each {|key, ary| ... } enum.chunk(initial_state) {|elt, state| key }.each {|key, ary| ... }
例として、整数列を連続する奇数/偶数に分ける例を見てみます。 「n.even?」の値が切り替わるところで区切られているのがわかるでしょう。
[3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5].chunk {|n| n.even? }.each {|even, ary| p [even, ary] } #=> [false, [3, 1]] # [true, [4]] # [false, [1, 5, 9]] # [true, [2, 6]] # [false, [5, 3, 5]]
このメソッドは各要素が既にソートされている場合に便利です。 以下の例では、テキスト辞書ファイル(中身がソートされている) に含まれる単語を先頭の文字ごとに数えています。
# line.ord は先頭の文字のコードポイントを返す open("/usr/share/dict/words", "r:iso-8859-1") {|f| f.chunk {|line| line.ord }.each {|ch, lines| p [ch.chr, lines.length] } } #=> ["\n", 1] # ["A", 1327] # ["B", 1372] # ["C", 1507] # ["D", 791] # ...
さらにこのメソッドは以下の値を特別扱いします。
それ以外のアンダースコアで始まるシンボルを指定した場合は例外が発生します。
items.chunk { |item| :_underscore } # => RuntimeError: symbols beginning with an underscore are reserved
nil、 :_separator はある要素を無視したい場合に用います。 例として svn log の出力のハイフンの所で区切りたい場合を考えます。
sep = "-"*72 + "\n" # ハイフンが72個の行 IO.popen("svn log README") {|f| f.chunk {|line| line != sep || nil }.each {|_, lines| pp lines } } #=> ["r20018 | knu | 2008-10-29 13:20:42 +0900 (Wed, 29 Oct 2008) | 2 lines\n", # "\n", # "* README, README.ja: Update the portability section.\n", # "\n"] # ["r16725 | knu | 2008-05-31 23:34:23 +0900 (Sat, 31 May 2008) | 2 lines\n", # "\n", # "* README, README.ja: Add a note about default C flags.\n", # "\n"] # ...
テキストを空行で区切られた段落に分けたい場合にも nil が使えます。
File.foreach("README").chunk {|line| /\A\s*\z/ !~ line || nil }.each {|_, lines| pp lines }
「:_alone」は要素を素通ししたい場合に用います。 以下の例では「Foo#bar」という形式の行が連続している場合のみ チャンク化し、それ以外は素通しします。
pat = /\A[A-Z][A-Za-z0-9_]+\#/ open(filename) {|f| f.chunk {|line| pat =~ line ? $& : :_alone }.each {|key, lines| if key != :_alone print lines.sort.join('') else print lines.join('') end } }
チャンク化に状態遷移が必要な場合は、 オプション引数 initial_state に状態を保持するオブジェクトを渡します。 この場合、ブロックの第2引数にはこのオブジェクトが dup で複製 されて渡されます。