我有一个数组:
times = [2, 5, 7.5, 8.5, 9, 10, 11.5, 13.5, 14.5, 17, 18, 19, 24]
我希望用户输入一个时间,说"11",然后返回"11.5"(times.index(6)
),因为它大于10
但小于11.5
。
有没有办法在 Ruby 中做到这一点?
我的回答建议在times
很大时有效的方法。
如果像问题中一样,times
被排序,我们可能需要执行二叉搜索:
times = [2, 5, 7.5, 8.5, 9, 10, 11.5, 13.5, 14.5, 17, 18, 19, 24]
times.bsearch { |x| x >= 11 }
#=> 11.5
如果times.max < 11
,则返回nil
。
参见 Array#bsearch。
现在假设times
没有排序:
times.shuffle!
#=> [7.5, 2, 14.5, 9, 17, 5, 19, 24, 8.5, 11.5, 13.5, 10, 18]
当然,我们可以对times
进行排序,然后应用bsearch
,但排序是昂贵的,具有O(n*ln(n))的时间复杂度)。如果我们希望在不更改times
的情况下对多个目标值(例如,11
、12
...)重复该操作,则一次对times
进行排序的开销可能是合理的,但是如果我们希望仅对单个目标值(例如11
)执行该操作,则简单地执行线性搜索会更有效:
times.min_by { |n| n >= 11 ? (n-11) : Float::INFINITY }
#=> 11.5
如果times.max < 11
,则返回Float::INFINITY
。
请参阅枚举#min_by。
使用范围和===
:
如果 obj 介于范围的开始和结束之间,则返回
true
,否则false
返回(与cover?
相同)。
(1..5) === 0 # => false
(1..5) === 1 # => true
(1..5) === 5 # => true
(1..5) === 6 # => false
如果您希望范围是独占的,则可以使用...
:
(1...5) === 0 # => false
(1...5) === 1 # => true
(1...5) === 5 # => false
(1...5) === 6 # => false
但我不建议使用...
。调试时更难发现,并且愚弄了不了解其工作原理的人,这可能会引入错误。
范围可以使用s. 构造。e和s...e文字,或带有 ::new。使用
..
构造的范围从头到尾(包括开头)。使用...
创建的那些不包括结束值。
最好改用 4(或以前的值),这样可以完成相同的操作:
(1..4) === 0 # => false
(1..4) === 1 # => true
(1..4) === 5 # => false
(1..4) === 6 # => false
回到你的问题:
times = [2, 5, 7.5, 8.5, 9, 10, 11.5, 13.5, 14.5, 17, 18, 19, 24]
times.select { |i| (11 .. 11.5) === i } # => [11.5]
如果你想找到第一个大于给定数字的数字,假设数组是排序的,
times.find { |time | time > given_time }
如果未对数组进行排序,请先对其进行排序
times.sort.find { |time | time > given_time }