假设我有一个数组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]
答案 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}}索引的数组,这些索引已由块处理并且arr
为arr[i] #=> -n
。我选择了哈希结构进行快速键查找。该行
(processed[n] ||= []) << i
需要解释。首先,这是
的简写processed[n] = (processed[n] || []) << i
如果processed
有一个键n
(其值不是nil
),则上面表达式右侧的该键值是包含索引的非空数组i
为arr[i] #=> -n
,因此上述表达式缩减为
processed[n] = processed[n] << i
并将索引i
添加到数组中。如果processed
没有密钥n
,processed[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]]