Ruby:将数组的每个索引与同一数组的所有其他索引进行比较的惯用法:

时间:2016-09-16 21:00:13

标签: arrays ruby

假设我有一个数组arr = [7,0,4,-7],我希望获得[i, i2]arr[i] + arr[i2] == 0的索引。在示例中,答案为[0, 3]。这样做的惯用和有效方法是什么?

这是迄今为止我所获得的最好成绩。我确信这不是最好的方法。以前我使用两个while循环,但我觉得这没有任何好转。

> nums = [7,0,4,-7]

> nums.each_index do |n1|
    (nums.length).times do |n2|
      return [n1, n2] if nums[n1] + nums[n2] == 0
    end
  end

> [0, 3]

3 个答案:

答案 0 :(得分:3)

以下代码将为您找到总和为零的所有元素对。

arr = [7,0,4,-7, -4, 5]
zero_sum = arr.combination(2).select { |pair| pair.first + pair.last == 0 }
zero_sum #=> [[7, -7], [4, -4]]

然后,您可以通过以下方式找到这些元素的索引:

zero_sum.map { |pair| [arr.index(pair.first), arr.index(pair.last)] } #=> [[0, 3], [2, 4]]

如果您只需要一对使用方法find而不是select

arr.combination(2)
   .find { |first, last| first + last == 0 } #=> [7, -7]
   .map { |num| arr.index(num) } # =>[0, 3]

答案 1 :(得分:2)

以下方法只需要一次通过数组。它返回数组元素的所有索引对,总和为零。

<强>代码

def zero_summing_pairs(arr)
  processed = {}
  arr.each_with_index.with_object([]) do |(n,i),pairs|
    processed[-n].each { |j| pairs << [j,i] } if processed.key?(-n)
    (processed[n] ||= []) << i
  end
end

<强>实施例

zero_summing_pairs [7,0,4,-7]
  #=> [[0, 3]] 
zero_summing_pairs [7,4,0,7,4,0,-7,-4,-7]
  #=> [[2, 5], [0, 6], [3, 6], [1, 7], [4, 7], [0, 8], [3, 8]]

相关值如下。

arr = [7,0,4,-7]
zero_summing_pairs(arr).map { |i,j| [arr[i], arr[j]] }
  #=> [[7, -7]] 

arr = [7,4,0,7,4,0,-7,-4,-7]
zero_summing_pairs(arr).map { |i,j| [arr[i], arr[j]] }
  #=> [[0, 0], [7, -7], [7, -7], [4, -4], [4, -4], [7, -7], [7, -7]]

<强>解释

  • pairs是值arr的索引对的数组,总和为零。 pairs是方法返回的对象。
  • processed是一个哈希,其密钥等于块已处理的arr的值。每个键k的值是i的{​​{1}}索引的数组,这些索引已由块处理并且arrarr[i] #=> -n。我选择了哈希结构进行快速键查找。

该行

(processed[n] ||= []) << i

需要解释。首先,这是

的简写
processed[n] = (processed[n] || []) << i

如果processed有一个键n(其值不是nil),则上面表达式右侧的该键值是包含索引的非空数组iarr[i] #=> -n,因此上述表达式缩减为

processed[n] = processed[n] << i

并将索引i添加到数组中。如果processed没有密钥nprocessed[n]等于nil,那么表达式就会变为

processed[n] = (processed[n] || []) << i
             = (nil || []) << i      
             = [] << i
             = [i]

换句话说,此处键n的值为空数组,然后i附加到该数组。

现在让我们逐步完成

的代码
arr = [7,0,4,-7]

processed = {}
enum0 = arr.each_with_index
  #=> #<Enumerator: [7, 0, 4, -7]:each_with_index>

我们可以看到这个枚举器通过将它转换为数组而生成的值。

enum0.to_a
  #=> [[7, 0], [0, 1], [4, 2], [-7, 3]] 

继续,

enum1 = enum0.with_object([])
  #=> #<Enumerator: #<Enumerator: [7, 0, 4, -7]:each_with_index>:with_object([])> 
enum1.to_a
  #=> [[[7, 0], []], [[0, 1], []], [[4, 2], []], [[-7, 3], []]] 

如果你检查enum1定义的返回值,你会发现它可以被认为是一个&#34;复合物&#34;枚举。在执行计算时,将填充空数组(对应于块变量pairs)。

生成enum1的第一个值并将其传递给块,并使用并行分配(又名多个赋值)为三个块变量赋值和消歧(又名 decompositon )。

(n,i), pairs = enum1.next
      #=> [[7, 0], []] 
n     #=> 7 
i     #=> 0
pairs #=> [] 

作为

processed.key?(-n)
  #=> processed.key?(-7)
  #=> false

未执行块的第一行。该块的第二行是

(processed[n] ||= []) << i
  #=> processed[n]
  #=> [i]
  #=> [0]

所以现在

processed
  #=> {7=>[0], 0=>[1]}
pairs
  #=> [] 

enum1生成的其余三个元素的处理方式类似。

(n,i), pairs = enum1.next
  #=> [[0, 1], []] 
processed.key?(-n)
  #=> processed.key?(0)
  #=> false 
(processed[n] ||= []) << i
  #=> (processed[0] ||= []) << 1
  #=> [] << 1
  #=> [1]
processed
  #=> {7=>[0], 0=>[1]}
pairs
  #=> [] 

(n,i), pairs = enum1.next
  #=> [[4, 2], []] 
processed.key?(-n)
  #=> processed.key?(-4)
  #=> false 
(processed[n] ||= []) << i
  #=> (processed[4] ||= []) << 2
  #=> [] << 2
  #=> [2] 
processed
  #=> {7=>[0], 0=>[1], 4=>[2]} 
pairs
  #=> [] 

(n,i), pairs = enum1.next
  #=> [[-7, 3], []] 
processed.key?(-n)
  # processed.key?(7)
  #=> true 
processed[-n].each { |j| pairs << [j,i] }
  # processed[7].each { |j| pairs << [j,3] }
  #=> [0] 
(processed[n] ||= []) << i
  #=> (processed[-7] ||= []) << 3
  #=> [] << 3
  #=> [3] 
processed
  #=> {7=>[0], 0=>[1], 4=>[2], -7=>[3]} 
pairs
  #=> [[0, 3]] 

请注意enum1生成的最后一个值是第一个在processed中匹配的值,因此与块计算中的先前值的处理方式不同。最后,

(n,i), pairs = enum1.next
  #=> StopIteration: iteration reached an end (an exception)

导致pairs从块返回,因此从方法返回。

答案 2 :(得分:2)

这是一种方法,它使用Array#combination,类似于@kallax的其他答案,但适用于索引的组合而不是元素的组合:

arr = [7,0,4,-7]
(0...arr.size).to_a.combination(2).select {|i| arr[i.first] + arr[i.last] == 0}
#=> [[0, 3]]