Ruby:如何通过组合和交错两个其他数组来创建数组

时间:2014-01-29 17:44:52

标签: ruby arrays

或许,提出一个更普遍的问题是如何在Ruby中进行列表理解。

假设给出一个数字N(比如N = 5),我想得到一个这样的数组:

[[0, 1], [0, 2], [0, 3], [0, 4], [1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]

我可以使用命令式方法:

  arr = []
  N = 5
  (0..N-1).each do |i|
    (i+1..N-1).each do |j|
      arr << [i, j]
    end
  end
  puts arr

使用功能方式:

(0..N-1).collect{|el1| (el1+1..N-1).collect{|el2| [el1, el2]}}.flatten.each_slice(2).to_a

我不喜欢第二个例子依赖于数组按正确顺序排序的事实。 是否有更简洁的方法以功能的方式获得阵列(没有额外的展平和切片)?

3 个答案:

答案 0 :(得分:2)

我会这样做:

n = 5
a = n.times.flat_map do |i|
  [i].product (i+1..n-1).to_a
end
a # => [[0, 1], [0, 2], [0, 3], [0, 4], [1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]

答案 1 :(得分:1)

你可以这样做:

Array(0...N).combination(2).to_a

看起来不错,但缺点是它会产生不使用的N!/(4 *(N-2)!)组合。

编辑:我原来在上面用select { |x,y| x < y }代替to_a。 @Stefan指出select是多余的。也许我的大脑有permutation(2)

这是另一种方式,@ Arup答案的变体:

a = Array(0...N)
a.size.times.reduce([]) { |b,_| b + [a.shift].product(a) }

答案 2 :(得分:0)

最有效的方法是Stefan's,这是对Cary的答案的评论(修改为在Arup对此答案的评论中使用n变量),这是对Cary的回答的修改,所以+1给所有人那些家伙:

2.1.0p0 :001 > n = 5
 => 5 
2.1.0p0 :002 > a = (0...n).to_a.combination(2).to_a
 => [[0, 1], [0, 2], [0, 3], [0, 4], [1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]] 

一些基准:

2.1.0p0 :001 > require 'benchmark'
 => true 
2.1.0p0 :002 > n = 5
 => 5 
2.1.0p0 :003 > puts Benchmark.measure { 1000000.times { a = n.times.flat_map {|i| [i].product (i+1..n-1).to_a} } }
  8.050000   0.010000   8.060000 (  8.051535)
 => nil 
2.1.0p0 :004 > puts Benchmark.measure { 1000000.times { a = n.times.flat_map {|x| (x+1..n-1).map{|y| [x,y]}} } }
  6.250000   0.000000   6.250000 (  6.249600)
 => nil
2.1.0p0 :005 > puts Benchmark.measure { 1000000.times { a = Array(0...n).combination(2).select { |x,y| x < y } } }
  5.110000   0.010000   5.120000 (  5.120506)
 => nil 
2.1.0p0 :006 > puts Benchmark.measure { 1000000.times { a = n.times.to_a.combination(2).to_a } }
  4.050000   0.000000   4.050000 (  4.045895)
 => nil 
2.1.0p0 :007 > puts Benchmark.measure { 1000000.times { a = Array(0...n).combination(2).to_a } }
  3.920000   0.000000   3.920000 (  3.928282)
 => nil 
2.1.0p0 :008 > puts Benchmark.measure { 1000000.times { a = (0...n).to_a.combination(2).to_a } }
  3.520000   0.000000   3.520000 (  3.522056)
 => nil