我在Ruby Core中寻找一个Array等效的String#分裂,并惊讶地发现它不存在.有没有比以下更优雅的方式将数组拆分为基于值的子数组?
class Array def split( split_on=nil ) inject([[]]) do |a,v| a.tap{ if block_given? ? yield(v) : v==split_on a << [] else a.last << v end } end.tap{ |a| a.pop if a.last.empty? } end end p (1..9 ).to_a.split{ |i| i%3==0 },(1..10).to_a.split{ |i| i%3==0 } #=> [[1,2],[4,5],[7,8]] #=> [[1,8],[10]]
编辑:对于那些感兴趣的人来说,引发这个请求的“真实世界”的问题可以在this answer中看到,在这里我用了@ fd的下面的答案来实现.
解决方法
我尝试打高尔夫球,但仍然不是一个单一的方法:
(1..9).chunk{|i|i%3==0}.reject{|sep,ans| sep}.map{|sep,ans| ans}
或更快:
(1..9).chunk{|i|i%3==0 || nil}.map{|sep,ans| sep&&ans}.compact
此外,Enumerable#chunk似乎是Ruby 1.9,但它非常接近你想要的.
例如,原始输出将是:
(1..9).chunk{ |i|i%3==0 }.to_a => [[false,[1,2]],[true,[3]],[false,5]],[6]],8]],[9]]]
(to_a是使irb打印一些好东西,因为块给你一个枚举器而不是一个数组)
编辑:请注意,上述优雅的解决方案比最快的实施速度慢2-3倍:
module Enumerable def split_by result = [a=[]] each{ |o| yield(o) ? (result << a=[]) : (a << o) } result.pop if a.empty? result end end