所以我正在解决这些练习问题,也许有更好的方法可以做到这一点,但这就是我所得到的。我感到非常困惑,为什么有时候这似乎只起作用...
def nearest_larger(arr, idx)
bigs = []
arr.each do |num|
if num > arr[idx]
bigs << num
end
end
sorted = bigs.sort
if sorted.length > 1
sorted = sorted[0]
end
return arr.index(sorted)
end
puts nearest_larger([2, 3, 4, 8], 2) #DOES NOT WORK
puts nearest_larger([2, 3, 4, 8], 2) #DOES WORK
puts nearest_larger([8, 8, 4, 2], 2) #ALSO WORKS... why?!!!
答案 0 :(得分:1)
由于我不知道您正在执行的练习,因此我不清楚该函数的确切功能,但是我看到的最明显的问题是您有时在检查一个数组是否包含另一个数组,有时检查它的实际元素。可疑块尤其是if sorted.length > 1; sorted = sorted[0]; end
。
在您的第一个无效呼叫中,只有一个数字大于索引2
,即8。sorted
在这种情况下的长度仅为{{1} }-因此,由于您的if语句,它不会将其从数组更改为第一项。
从某种意义上讲,第二种情况也不起作用。
您的代码的经过稍微修改的工作版本如下。
1
较小的版本会这样:
def nearest_larger(arr, idx)
larger_numbers = []
arr.each do |num|
if num > arr[idx]
larger_numbers << num
end
end
smallest_larger_number = larger_numbers.sort()[0]
return arr.index(smallest_larger_number)
end
答案 1 :(得分:1)
给出一个数组a
和一个数组索引i
,假设idxa
是j
的索引a
的数组,其中a[j] > a[i]
。如果idxa
为空,则返回nil
;否则问题是在k
中找到一个索引idxa
的索引,其中(k-i).abs
是最小值。如果idx
包含多个索引k
,而索引(k-i).abs
最小,则可以返回这些索引中的任何一个。
选择索引并找到最接近的
这是解决问题的简单但不是特别有效的方法。
def nearest_larger(arr, idx)
v = arr[idx]
a = arr.each_index.select { |i| arr[i] > v }
return nil if a.empty?
a.min_by { |i| (i-idx).abs }
end
test = [
[[2, 3, 4, 8], 2],
[[8, 5, 4, 3], 2],
[[8, 3, 4, 2], 2],
[[8, 5, 8, 2], 2]
]
test.each do |arr, idx|
i = nearest_larger(arr, idx)
puts "#{arr} idx = #{idx}: closest idx = #{i.nil? ? "nil" : i}"
end
[2, 3, 4, 8] idx = 2: closest idx = 3
[8, 5, 4, 3] idx = 2: closest idx = 1
[8, 3, 4, 2] idx = 2: closest idx = 0
[8, 5, 8, 2] idx = 2: closest idx = nil
让我们检查一下arr
和idx
的这些值的步骤:
arr = [8, 5, 4, 3]
idx = 2
v = arr[idx]
#=> 4
e = arr.each_index
#=> #<Enumerator: [8, 5, 4, 3]:each_index>
如您所见,方法Array#each_index在arr
上调用时将返回一个枚举数。可以将其视为产生价值的机器。我们可以将枚举器转换为数组,以查看它们将生成什么值:
e.to_a
#=> [0, 1, 2, 3]
继续
a = e.select { |i| arr[i] > v }
#=> [0, 1]
e
将元素传递到Enumerable#select,然后依次传递到块,将块变量i
分配给它们的值。实际上,我们可以写
ee = e.select
#=> #<Enumerator: #<Enumerator: [8, 5, 4, 3]:each_index>:select>
ee.to_a
#=> [0, 1, 2, 3]
a = ee.each { |i| arr[i] > v }
#=> [0, 1]
ee
可以被视为化合物枚举器。如果最后一点令人困惑,请暂时忘记它。
继续
return nil if a.empty?
a
不为空,因此我们不返回。最后一步如下。
a.min_by { |i| (i-idx).abs }
#=> 1
请注意,我可以将arr.each_index
替换为arr.size.times
(请参阅Integer#times)或替换为0.up_to(arr.size-1)
(请参阅Integer#upto)。
选中任一侧,然后向前移动一个,直到找到更大的值
我们可以以增加复杂性为代价来提高效率。实际上,以下代码不是很像Ruby,并且imo不太吸引人。
def nearest_larger(arr, idx)
v = arr[idx]
last = arr.size-1
iup, idn = idx + 1, idx - 1
while iup <= last || idn >= 0
if iup <= last
return iup if arr[iup] > v
iup += 1
end
if idn >= 0
return idn if arr[idn] > v
idn -= 1
end
end
nil
end
test.each do |arr, idx|
i = nearest_larger(arr, idx)
puts "#{arr} idx = #{idx}: closest idx = #{i.nil? ? "nil" : i}"
end
[2, 3, 4, 8] idx = 2: closest idx = 3
[8, 5, 4, 3] idx = 2: closest idx = 1
[8, 3, 4, 2] idx = 2: closest idx = 0
[8, 5, 8, 2] idx = 2: closest idx = nil