Ruby 用更灵活的解决方案替换if语句

Ruby 用更灵活的解决方案替换if语句,ruby,Ruby,我有一个产品类,它的属性是代码。代码始终是一个数字,根据第一位数字,产品属于某种类型 If first digit in 0,1,2,3 product is a 'A type' If first digit in 4,5,6 product is a 'B type' If first digit in 7,8,9 product is a 'C type' 我正在寻找一种不用3分支if语句来确定产品类型的方法 有什么想法吗?您是否考虑过使用案例陈述?我不确定这是否满足你想要摆脱“3分支i

我有一个产品类,它的属性是代码。代码始终是一个数字,根据第一位数字,产品属于某种类型

If first digit in 0,1,2,3 product is a 'A type'
If first digit in 4,5,6 product is a 'B type'
If first digit in 7,8,9 product is a 'C type'
我正在寻找一种不用3分支
if
语句来确定产品类型的方法


有什么想法吗?

您是否考虑过使用
案例
陈述?我不确定这是否满足你想要摆脱“3分支if语句”的愿望,但也许它会给你一些其他的考虑。
case code[0].to_i
when 0..3 then 'A type'
when 4..6 then 'B type'
when 7..9 then 'C type'
end
我在上面假设“code”属性实际上存储为字符串,因为您指定第一个数字可以是0,在Ruby中,如果它是一个文本整数,它会将您的数字转换为八进制。如果这是一个错误的假设,只需更改代码[0]位


这有帮助吗?

您是否考虑过使用
案例
语句?我不确定这是否满足你想要摆脱“3分支if语句”的愿望,但也许它会给你一些其他的考虑。
case code[0].to_i
when 0..3 then 'A type'
when 4..6 then 'B type'
when 7..9 then 'C type'
end
def func(code)
  return 'A type' if code[0] == '0'
  ['A','B','C'][(code[0].to_i-1)/3] << ' type'
end

func('0ekrnn')   # => 'A type'
func('4mgm')     # => 'B type'
我在上面假设“code”属性实际上存储为字符串,因为您指定第一个数字可以是0,在Ruby中,如果它是一个文本整数,它会将您的数字转换为八进制。如果这是一个错误的假设,只需更改代码[0]位

这有帮助吗?

def func(代码)
def func(code)
  return 'A type' if code[0] == '0'
  ['A','B','C'][(code[0].to_i-1)/3] << ' type'
end

func('0ekrnn')   # => 'A type'
func('4mgm')     # => 'B type'
如果代码[0]=“0”,则返回“A类型” ['A'、'B'、'C'][(代码[0]。收件人i-1)/3]“A类型” func('4mgm')#=>“B型”
def func(代码)
如果代码[0]=“0”,则返回“A类型”
['A'、'B'、'C'][(代码[0]。收件人i-1)/3]“A类型”
func('4mgm')#=>“B型”

您可以使用三元运算符

first_char = code[0].to_i
product_type = [0,1,2,3].include?(first_char) ? "A" : [4,5,6].include?(first_char) ? "B" : [7,8,9].include?(first_char) ? "C" : ""

可以使用三元运算符

first_char = code[0].to_i
product_type = [0,1,2,3].include?(first_char) ? "A" : [4,5,6].include?(first_char) ? "B" : [7,8,9].include?(first_char) ? "C" : ""

一种面向对象的方法。显然,
match?
方法可以以最符合您需求的任何方式编写,也可以根据您的需求变化进行调整——我在这里使用了regex来帮助演示这种方法的灵活性。方法的
TYPES
常量和
typeu应该封装在某个地方,但具体位置由您决定

class Type
  def initialize name, pattern
    @name = name
    @pattern = pattern
  end

  def match? code
    code =~ @pattern
  end
end

a_type = Type.new 'A', /^[0-3]/
b_type = Type.new 'B', /^[4-6]/
c_type = Type.new 'C', /^[7-9]/
TYPES = [a_type, b_type, c_type]

def type_for product
  TYPES.detect { |type| type.match? product.code }
end

一种面向对象的方法。显然,
match?
方法可以以最符合您需求的任何方式编写,也可以根据您的需求变化进行调整——我在这里使用了regex来帮助演示这种方法的灵活性。
方法的
TYPES
常量和
typeu应该封装在某个地方,但具体位置由您决定

class Type
  def initialize name, pattern
    @name = name
    @pattern = pattern
  end

  def match? code
    code =~ @pattern
  end
end

a_type = Type.new 'A', /^[0-3]/
b_type = Type.new 'B', /^[4-6]/
c_type = Type.new 'C', /^[7-9]/
TYPES = [a_type, b_type, c_type]

def type_for product
  TYPES.detect { |type| type.match? product.code }
end

我倾向于在自己的代码中使用类似的东西,只是因为我更愿意定义一个表,显示与匹配值和预期输出的关系:

HASH = {
  /\A[0-3]/ => 'A type',
  /\A[4-6]/ => 'B type',
  /\A[7-9]/ => 'C type'
}

def get_type(s)
  HASH.keys.each { |regex| 
    return HASH[regex] if s[regex]
  }
end

[ '0001', '3000', '4000', '9000' ].each do |v|
  puts "#{ v } => #{ get_type(v) }"
end
哪些产出:

0001 => A type
3000 => A type
4000 => B type
9000 => C type
我尝试在YAML文件中保留哈希之类的内容,这样我们就不必修改代码来添加额外的测试/类型。可以使用以下文件中的
YAML::load_file()
轻松初始化哈希常量:

--- ? !ruby/regexp /\A[4-6]/ : B type ? !ruby/regexp /\A[0-3]/ : A type ? !ruby/regexp /\A[7-9]/ : C type --- ? !ruby/regexp/\A[4-6]/ :B型 ? !ruby/regexp/\A[0-3]/ :A型 ? !ruby/regexp/\A[7-9]/ :C类型 并通过一个简单的
将HASH.to_yaml
放入创建


也就是说,我强烈支持使用
case
语句方法。

我倾向于在自己的代码中使用类似的东西,因为我更喜欢定义一个表,显示与匹配值和预期输出的关系:

HASH = {
  /\A[0-3]/ => 'A type',
  /\A[4-6]/ => 'B type',
  /\A[7-9]/ => 'C type'
}

def get_type(s)
  HASH.keys.each { |regex| 
    return HASH[regex] if s[regex]
  }
end

[ '0001', '3000', '4000', '9000' ].each do |v|
  puts "#{ v } => #{ get_type(v) }"
end
哪些产出:

0001 => A type
3000 => A type
4000 => B type
9000 => C type
我尝试在YAML文件中保留哈希之类的内容,这样我们就不必修改代码来添加额外的测试/类型。可以使用以下文件中的
YAML::load_file()
轻松初始化哈希常量:

--- ? !ruby/regexp /\A[4-6]/ : B type ? !ruby/regexp /\A[0-3]/ : A type ? !ruby/regexp /\A[7-9]/ : C type --- ? !ruby/regexp/\A[4-6]/ :B型 ? !ruby/regexp/\A[0-3]/ :A型 ? !ruby/regexp/\A[7-9]/ :C类型 并通过一个简单的
将HASH.to_yaml
放入创建


话虽如此,我还是强烈支持一种陈述的方式。

谢谢你的回复。是,代码存储为字符串,因为实际上代码可能还包含字符,但第一个字符始终是数字。case语句实际上并没有满足我对“清洁”的要求,因为我认为if语句没有太大的改进。+1没有对类型和代码之间的关系做出超出问题中所述的假设。谢谢你的回答。是,代码存储为字符串,因为实际上代码可能还包含字符,但第一个字符始终是数字。case语句实际上并没有满足我对“干净”的渴望,因为我没有看到if语句有什么大的改进。+1没有对类型和代码之间的关系做出超出问题中所述的假设。这与其说是“设计”改进,不如说是“语法”改进(如果我们可以称之为改进)。无论如何,谢谢你的帮助。这与其说是“设计”的改进,不如说是“语法”的改进(如果我们可以称之为改进的话)。无论如何,感谢您的帮助。这会对代码和类型之间的关系做出可能不正确的假设。这会对代码和类型之间的关系做出可能不正确的假设。这属于。这已经是最简单的了。即使你想出了一些奇特的方法,当进入机器代码级别时,它仍然会做类似的事情。这已经是最简单的了。即使你想出了一些奇特的方法,当进入机器代码级别时,它仍然会做类似的事情。不过,对我来说,使用散列只对所有数据进行迭代(从不单独访问密钥)似乎很奇怪(不知道为什么)。我不认为这很奇怪,它只是对它使用散列,一种类型的数据到另一种类型的数据的映射。使用子数组也可以做类似的事情,但是
=>
有助于直观地提醒我们,这两个数组是绑定在一起以维护代码的。+1我正在考虑用类似的方式回答。仅使用散列遍历所有散列(从不访问)