Ruby 1.9.2
標準クラス・モジュール > Enumerable > chunk
enum.chunk {|item| block }
chunkメソッドは、ブロックの戻り値ごとに要素の並びをまとめた配列を作ります。戻り値はEnumeratorオブジェクトです。Enumeratorオブジェクトのeachメソッドを呼び出すと、eachのブロック引数には「chunkのブロックの戻り値、戻り値に対応する配列」が入ります。
次の例は、文字列中の各文字をcharsメソッドで取り出し、chunkメソッドでEnumeratorを作ります。chunkのブロックでは、英数字(:word)かそれ以外(:other)で文字を分類します。Enumeratorのeachを呼び出すと、chunkの戻り値ごとにまとめられた配列を取り出せます。
enum = "Ruby is cool!".chars.chunk {|ch| ch =~ /\w/ ? :word : :other }
enum.each {|key, arr| puts "#{key}: #{arr.inspect}" }
word: ["R", "u", "b", "y"] other: [" "] word: ["i", "s"] other: [" ", " "] word: ["c", "o", "o", "l"] other: ["!"]
上記の例は、メソッドチェーンを使って次のように書けます。
"Ruby is cool!".chars.chunk {|ch|
ch =~ /\w/ ? :word : :other
}.each {|key, arr|
puts "#{key}: #{arr.inspect}"
}
chunkのブロックでnilまたは:_separatorを返すと、Enumeratorのeachにはその要素は含まれなくなります。
"Ruby is cool!".chars.chunk {|ch|
ch =~ /\w/ ? :word : nil
}.each {|key, arr|
puts "#{key}: #{arr.inspect}"
}
word: ["R", "u", "b", "y"] word: ["i", "s"] word: ["c", "o", "o", "l"]
chunkのブロックで:_aloneを返すと、要素をまとめた配列ではなく、1要素からなる配列ができます。次の例では、英数字でも空白でもない文字を1つずつ取り出します。
"Ruby is cool!?".chars.chunk {|ch|
case ch
when /\w/ then :word
when /\s/ then nil
else :_alone
end
}.each {|key, arr|
puts "#{key}: #{arr.inspect}"
}
word: ["R", "u", "b", "y"] word: ["i", "s"] word: ["c", "o", "o", "l"] _alone: ["!"] _alone: ["?"]
enum.chunk(state) {|item, state| block }
chunkメソッドの引数にオブジェクトを渡すと、ブロック中でそのオブジェクトをメモ代わりに利用できます。オブジェクトはブロックの第2引数に入ります。オブジェクトはdupでコピーされるので、数値などdupできないオブジェクトは渡せません。
次の例では、引数にハッシュを渡して「前の文字」を記録し、連続した空白を1要素からなる配列にしています。
"Ruby is cool!?".chars.chunk({}) {|ch, memo|
last, memo[:last] = memo[:last], ch
case ch
when /\w/ then :word
when /\s/ then last =~ /\s/ ? nil : :space
else :_alone
end
}.each {|key, arr|
puts "#{key}: #{arr.inspect}"
}
word: ["R", "u", "b", "y"] space: [" "] word: ["i", "s"] space: [" "] word: ["c", "o", "o", "l"] _alone: ["!"] _alone: ["?"]
slice_before : 要素の並びを正規表現で分割。