这是我的任务:
输入:键盘上的数字列表
输出:列表中第二小的数字,以及它在列表中的位置,其中 1 是第一个数字的位置。
这是我到目前为止的代码:
values = []
print "Enter a number: "
a = gets.chomp.to_i
values.push(a)
print "Enter another number: "
b = gets.chomp.to_i
values.push(b)
print "Enter another number: "
c = gets.chomp.to_i
values.push(c)
print "Enter a final number: "
d = gets.chomp.to_i
values.push(d)
new_values = values.sort
second_smallest = new_values[1]
puts "Second smallest number: #{second_smallest}"
if values.include? second_smallest
print "found matching element"
end
我能够从排序的副本中抓取第二小的元素,然后在原始数组中检查该元素。如何抓取原始数组中匹配元素的索引并打印给用户?
对不起,如果很简单,我是红宝石的新手
def second_smallest(arr)
smallest = arr.min
arr.each_with_index.reject { |n,_| n == smallest }.min_by(&:first)
end
second_smallest [3, 1, 4, 1, 2, 3, 5] #=> [2, 4]
second_smallest [1, 1, 1] #=> nil
second_smallest [] #=> nil
在第一个示例中,第二小的数字显然是2
。
Ruby在Enumerable
和Enumerator
上有几个方便的方法,特别是Enumerator#with_index
和Enumerable#min_by
。因此,您可以执行以下操作:
_, (value, position) = values.each.with_index(1).min_by(2) { |value, _| value }
puts "Second smallest number is #{value} found at position #{position}"
如果你不给它一个块,each
方法会返回一个Enumerator
,这允许你链接with_index
,用1
传递它的可选参数offset
,所以第一个元素是索引 1 而不是索引 0。
现在,枚举器将对[value's element, index]
集合进行操作,我们就此调用min_by
,告诉它我们想要 2 个最小值,并将块参数中的参数拆分为value
和 ruby 的"未使用"变量_
。那么,如果我们忽略指数,为什么还要调用with_index
呢?好吧,现在min_by
返回具有 2 个最小value's element
的[value's element, index]
,我们将最小的分流回"未使用的"变量_
,让 ruby 将下一个数组(第二个最小的数组)转换为 2 个变量value
和position
,分别包含最小的元素和索引(我倾向于使用 position 来表示某物是基于 1 的,索引来表示它是基于 0 的, 但这只是个人怪癖)。然后我们可以将它们显示给最终用户。
但是请注意,在调用此数组之前,您不希望对values
数组进行排序。如果这样做,您将始终看到第二个最小的元素位于位置 2。(所以在你的示例代码中,你想处理values
而不是new_values
,new_values
消失了)
如果你想要其他变体,你可以更多地使用min_by
及其返回值,例如,如果你只想要第三个最小的值,你可以这样做:
*_, (value, position) = values.each.with_index(1).min_by(3) { |value, _| value }
同样的事情,除了 splat 运算符在开始时*
,将除最后一个元素之外的所有元素放入该"未使用"变量中。如果你想要第二和第三小,你可以做:
*_, (second_smallest_value, second_smallest_position), (third_smallest_value, third_smallest_position) = values.each.with_index(1).min_by(3) { |value, _| value }
解构并在变量中存储min_by
的最后 2 个返回值。或者只是
*_, second_smallest, third_smallest = values.each.with_index(1).min_by(3) { |value, _| value }
存储数组而不将它们解构为单个变量(因为它开始变得拗口)