我正在尝试根据值数组动态生成case语句。例如,假设我有一个范围数组
[1..3,4..6,7..20,21..38]
我想写一个动态case语句,它返回任何范围的第一个数字
case n
ranges.each do |r|
when r
r.first
end
end
这是可能的,还是我必须找到另一种方法(我的实际代码更复杂)?
答案 0 :(得分:4)
如果我的问题是正确的,那么您可以忘记case
声明并使用detect执行此操作:
ary = [1..3, 4..6, 7..20, 21..38]
num = 15 # say
ary.detect { |sub_ary| sub_ary.include?(num) }
=> 7..20
ary.detect { |sub_ary| sub_ary.include?(num) }.first # call `first` on result of above, which is a range, to get the first element.
=> 7
答案 1 :(得分:3)
出于好奇:
number = 5
instance_eval [
"case number",
*ranges.map { |r| "when #{r} then (#{r}).first" },
"end"
].join($/)
#⇒ 4
答案 2 :(得分:1)
除了 #detect (或 #find )以及来自Jagdeep Singhs answer的 #include? em>,您还可以使用案例等于运算符(Range#===
)。 case语句使用此运算符将输入值与您提供的方案进行比较。
ranges.find { |range| range === n }.first
如果找不到任何值,请记住 #detect 和 #find 返回nil
。这意味着您可能希望使用安全导航操作符(}&.first
)来防止nil
上的 #first 无方法例外,如果找不到该值
答案 3 :(得分:0)
这很好,但是有点毫无意义而且线程不安全:
def get_range(n)
ranges = [1..3,4..6,7..20,21..38]
case n
when 3
# special case
199
when ->(x) { @_get_range = ranges.find { |r| r.cover?(x) } }
@_get_range.first
else
0
end
ensure
remove_instance_variable(:@_get_range) if instance_variable_defined?(:@_get_range)
end
get_range(3) # => 199
get_range(5) # => 4
get_range(50) # => 0
您可以这样做:
ranges.find { |r| r.cover?(n) }&.first || 0
答案 4 :(得分:0)
我的两分钱。.
ranges = [1..3,4..6,7..20,21..38]
num = 15
ranges.bsearch { |range| range.member? num }.begin