在Ruby中将数组拆分为多个小数组的最佳方式

20

最简单的方法是根据某些条件将数组拆分为多个数组?在我的场景中,我需要将整数和字符串值移动到不同的数组中。我尝试了split方法,但效果不如预期。

x=[1,2,3,"a","b",4]
x.split {|item| item.kind_of? Fixnum}
在C#中,Linq提供了group by选项,可以根据条件对对象进行分组。是否有类似的方法可以在Object上使用(不使用ActiveRecord)?是否有简单的方法实现?
4个回答

42

你需要使用Enumerable#partition方法:

x = [1, 2, 3, "a", "b", 4]
numbers, not_numbers = x.partition{|item| item.kind_of?(Fixnum)}
# => [[1, 2, 3, 4], ["a", "b"]]

1
+1 这也是速度方面的一个稳定胜利!请查看我添加的基准测试。 - the Tin Man
6
下面的答案使用 group_by,它允许将数据分成多个组。 - Josh Diehl

8

在这里,我想再提供一些解决方案:

x = [1,2,3,"a","b",4]

numbers = x.select{ |e| e.is_a?(Fixnum) } # => [1, 2, 3, 4]
letters = x - numbers # => ["a", "b"]

numbers = x.select{ |e| e.kind_of?(Fixnum) } # => [1, 2, 3, 4]
letters = x - numbers # => ["a", "b"]

或者

(numbers, letters) = x.group_by {|a| a.class}.values_at(Fixnum, String)
numbers # => [1, 2, 3, 4]
letters # => ["a", "b"]

除此之外,还有一些基准测试显示微小的变化如何影响速度:

require 'benchmark'

x = [1,2,3,"a","b",4] * 100
n = 10_000
Benchmark.bm do |bench|
  bench.report { n.times {
    numbers = x.select{ |e| e.is_a?(Fixnum) }
    letters = x - numbers
  }}

  bench.report { n.times {
    numbers = x.select{ |e| e.kind_of?(Fixnum) }
    letters = x - numbers
  }}

  bench.report { n.times {
    (numbers, letters) = x.group_by {|a| a.class}.values_at(Fixnum, String)
  }}

  bench.report { n.times {
    numbers, not_numbers = x.partition{|item| item.kind_of? Fixnum}
  }}
end
# >>       user     system      total        real
# >>   4.270000   0.010000   4.280000 (  4.282922)
# >>   4.290000   0.000000   4.290000 (  4.288720)
# >>   5.160000   0.010000   5.170000 (  5.163695)
# >>   3.720000   0.000000   3.720000 (  3.721459)

奇怪的是,我发现.partition比创建2个数组并执行.eachif e.kind_of(Fixnum)还要快。我猜他们在C中对.partition进行了一些优化。 - Dogbert
我还没有看过源代码,但是我有同样的怀疑。 - the Tin Man

5

尝试:

x.group_by {|x| x.class}

您可以通过在结果上调用to_a,获得一个数组,例如您所给出的示例将返回:

[[Fixnum, [1, 2, 3, 4]], [String, ["a", "b"]]]

3
这是我的解决方案:
hash = x.group_by { |t| t.kind_of? Fixnum }
# hash  => {true=>[1, 2, 3, 4], false=>["a", "b"]} 
array1 = hash[true] # The array of integers
array2 = hash[false] # The array of strings

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接