或许,提出一个更普遍的问题是如何在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
我不喜欢第二个例子依赖于数组按正确顺序排序的事实。 是否有更简洁的方法以功能的方式获得阵列(没有额外的展平和切片)?
答案 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