Case for Ruby中的每个循环

时间:2018-06-19 07:44:42

标签: ruby

我正在尝试根据值数组动态生成case语句。例如,假设我有一个范围数组

[1..3,4..6,7..20,21..38]

我想写一个动态case语句,它返回任何范围的第一个数字

case n
  ranges.each do |r|
  when r
    r.first
  end
end

这是可能的,还是我必须找到另一种方法(我的实际代码更复杂)?

5 个答案:

答案 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?,您还可以使用案例等于运算符(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