Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby 根据值将数组拆分为子数组_Ruby_Arrays - Fatal编程技术网

Ruby 根据值将数组拆分为子数组

Ruby 根据值将数组拆分为子数组,ruby,arrays,Ruby,Arrays,我在Ruby Core中寻找一个数组等价物String#split,但惊讶地发现它并不存在。有没有比下面更优雅的方法根据值将数组拆分为子数组 class Array def split( split_on=nil ) inject([[]]) do |a,v| a.tap{ if block_given? ? yield(v) : v==split_on a << [] else a.la

我在Ruby Core中寻找一个数组等价物
String#split
,但惊讶地发现它并不存在。有没有比下面更优雅的方法根据值将数组拆分为子数组

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, 2], [4, 5], [7, 8], [10]]
类数组
def拆分(拆分打开=无)
注入([[])do | a,v|
a、 水龙头{
如果给定块,收益率(v):v==分割
a[[1,2]、[4,5]、[7,8]、[10]]

<强>编辑< /强>:对于那些感兴趣的人,可以看到引发这个请求的“真实世界”问题,在这里我用下面的FD的答案来实现。

< P>其他的方法你可能要考虑的是或

我不知道你希望它有多普遍,这里有一个方法

>> (1..9).each_slice(3) {|a| p a.size>1?a[0..-2]:a}
[1, 2]
[4, 5]
[7, 8]
=> nil
>> (1..10).each_slice(3) {|a| p a.size>1?a[0..-2]:a}
[1, 2]
[4, 5]
[7, 8]
[10]

我试过打高尔夫球,但还是没有一种方法:

(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, [4, 5]], [true, [6]], [false, [7, 8]], [true, [9]]]
(由于
chunk
提供的是一个枚举器而不是数组,因此
to_a
是为了让irb打印出一些漂亮的东西)


编辑:请注意,上述优雅的解决方案比最快的实现慢2-3倍:

模块可枚举
def拆分单位
结果=[a=[]]

每个{o{收益率(o)?(结果这里是汇总答案的基准(我不会接受这个答案):

正在测试的实现(在Ruby 1.9.2上):

类数组
def split_与_inject
注入([[])do | a,v|
a、 tap{yield(v)?(a这里是另一个(基准将其与最快的
split\u进行比较,每个
在这里):

需要“基准测试”
类数组
def拆分_与每个_
结果=[a=[]]
每个{o{产生(o)?(结果有时是这样做的好方法:

(1..6).partition { |v| v.even? } 
#=> [[2, 4, 6], [1, 3, 5]]

在Python中,您可以将其转换为字符串(值之间用逗号或其他符号分隔),将其拆分,然后返回列表。不知道这在Ruby中是否是一个选项。@Rafe应该是,但前提是内容仅为字符串。即使如此,这也很难被认为是优雅的:p@Phrogz如果它们是数字,它也可以工作。你只需执行
,'.连接([str(x)表示列表中的x])
,然后在任何情况下拆分,然后在逗号上重新加入并拆分。功能性,是的,优雅,呃不。@Rafe也许我也应该接受大多数迂回黑客的答案。到/从YAML,有人吗?:)仅供参考:在您的解决方案中,我没有看到任何要求
self
成为
数组的东西。您可以将该方法拉到
可枚举的
,因为您只依赖
self
响应
inject
(顺便说一句,这也将允许您在两个测试用例中摆脱
到a
)仅适用于我的特定mod 3示例,但不适用于一般情况。很好!我以前从未见过
chunk
。记录在案,它是1.9.2+,但我完全可以接受。这里有一个指向文档的链接:毫不奇怪(因为拒绝/映射需要额外的迭代)chunk稍微慢一点;我添加了一个基准测试“答案”收集实现。
(1..10)。chunk{n}n%3==0:_separator::keep}。map{uu,v | v}
(1..10)。chuck{n}n%3==0 | nil}。map{
虽然有点晚了,但是:这些方法并不完全可比,因为这些方法的结果并不完全相同。前三种方法返回的内容与
String#split
返回的内容类似(包括找到两个后续分隔符时的空数组),而
split_with_chunk
split_with_chunk 2
从不返回空数组,而
split_with_chunk 3
仍然包含chunk的“分组”值。这就像数组#分区,而不是字符串#拆分。与问题无关:作者想要拆分分隔的运行序列。
class Array
  def split_with_inject
    inject([[]]) do |a,v|
      a.tap{ yield(v) ? (a << []) : (a.last << v) }
    end.tap{ |a| a.pop if a.last.empty? }
  end

  def split_with_inject_no_tap
    result = inject([[]]) do |a,v|
      yield(v) ? (a << []) : (a.last << v)
      a
    end
    result.pop if result.last.empty?
    result
  end

  def split_with_each
    result = [a=[]]
    each{ |o| yield(o) ? (result << a=[]) : (a << o) }
    result.pop if a.empty?
    result
  end

  def split_with_chunk
    chunk{ |o| !!yield(o) }.reject{ |b,a| b }.map{ |b,a| a }
  end

  def split_with_chunk2
    chunk{ |o| !!yield(o) }.map{ |b,a| b ? nil : a }.compact
  end

  def split_with_chunk3
    chunk{ |o| yield(o) || nil }.map{ |b,a| b && a }.compact
  end
end
require 'benchmark'

class Array
  def split_with_each
    result = [a=[]]
    each{ |o| yield(o) ? (result << a=[]) : (a << o) }
    result.pop if a.empty?
    result
  end

  def split_with_each_2
    u, v = [], []
    each{ |x| (yield x) ? (u << x) : (v << x) }
    [u, v]
  end
end

a = *(1..5000); N = 1000
Benchmark.bmbm do |x|
  %w[ split_with_each split_with_each_2 ].each do |method|
    x.report( method ){ N.times{ a.send(method){ |i| i%3==0 || i%5==0 } } }
  end
end

                        user     system      total        real
split_with_each     2.730000   0.000000   2.730000 (  2.742135)
split_with_each_2   2.270000   0.040000   2.310000 (  2.309600)
(1..6).partition { |v| v.even? } 
#=> [[2, 4, 6], [1, 3, 5]]