Ruby重构类方法

ryevplcw  于 2022-12-29  发布在  Ruby
关注(0)|答案(3)|浏览(134)

我是ruby的新手,我正在尝试创建一个report_checker函数来检查单词“绿色,red,amber”出现的频率,并以如下格式返回:“绿色:2/n琥珀色:1/n红色:1”。
如果该单词不是所提到的免费单词之一,则将其替换为单词“unaccounted”,但仍计算其出现的次数。
我的代码返回repeats,例如,如果我给予它输入report_checker(“绿色,Amber,Green”),它返回“Green:2/n琥珀色:1/n绿色:2”,而不是“绿色:2/n琥珀色:1”。
而且,它不计算一个未计算的单词出现的次数。有什么指导我哪里出错了吗?

def report_checker(string)
  array = []
  grading = ["Green", "Amber", "Red"]

    input = string.tr(',', ' ').split(" ")
  
    input.each do |x|
       if grading.include?(x)
        array.push( "#{x}: #{input.count(x)}")
       else
         x = "Unaccounted"
        array.push( "#{x}: #{input.count(x)}")
       end
    end   
    
    array.join("/n")
end

 report_checker("Green, Amber, Green")

我试着将这些单词合并成单独的单词,并返回期望的单词及其计数

wbrvyc0a

wbrvyc0a1#

尝试吹代码
在方法之外添加显示逻辑

def report_checker(string, grading = %w[ Green Amber Red ])
  data = string.split(/\s*[,|\s]\s*/)
  unaccounted = data - grading
  (data - unaccounted).tally.merge('Unaccounted' => unaccounted.count)  
end

result = report_checker("Green, Amber, Green, Orange, Yellow")
result.each { |k,v| puts "#{k} : #{v}"}

产出

Green : 2
Amber : 1
Unaccounted : 2
yshpjwxd

yshpjwxd2#

这里有很多事情可以做,以将其引导到更惯用的Ruby中:

# Use a constant, as this never changes, and a Set, since you only care
# about inclusion, not order. Calling #include? on a Set is always
# quick, while on a longer array it can be very slow.
GRADING = Set.new(%w[ Green Amber Red ])

def report_checker(string)
  # Do this as a series of transformations:
  # 1. More lenient splitting on either comma or space, with optional leading
  #    and trailing spaces.
  # 2. Conversion of invalid inputs into 'Unaccounted'
  # 3. Grouping together of identical inputs via the #itself method
  # 4. Combining these remapped strings into a single string
  string.split(/\s*[,|\s]\s*/).map do |input|
    if (GRADING.include?(input))
      input
    else
      'Unaccounted'
    end
  end.group_by(&:itself).map do |input, samples|
    "#{input}: #{samples.length}"
  end.join("\n")
end

report_checker("Green, Amber, Green, Orange")

关于Ruby,您将了解到这样简单的Map可以转换为非常简单的Ruby代码。如果您不习惯,现在可能会觉得有点令人生畏,但请记住,转换的每个组件并没有那么复杂。此外,您可以运行到该点以查看发生了什么,甚至可以在中间使用.tap { |v| p v }.来扩展通过那里的内容。
进一步深入到Ruby领域,你可能会想使用符号,比如:green:amber,因为它们非常整洁,比如哈希键:{ green: 0, amber: 2 }等等。
虽然这是作为单个方法完成的,但将其分为两个关注点可能是有意义的:一个专注于计算报表本身,例如{ green: 2, amber: 1, unaccounted: 1 }这样的表单,另一个可以将该表单的报表转换为所需的输出字符串。

gg0vcinb

gg0vcinb3#

在Ruby中,有很多很多方法可以实现你的最终目标,我不想一一介绍,但我会花点时间指出代码中的几个关键问题,以便向你展示最值得注意的问题在哪里,并向你展示如何用我个人能想到的最少的修改来修复它:

问题#1:

if grading.include?(x)
array.push( "#{x}: #{input.count(x)}")

这会导致每次grading包含x时都会添加一个新的array元素。这解释了为什么会出现重复的数组元素("Green: 2/nAmber: 1/nGreen: 2")。我建议的解决方法是在方法定义的最后一行使用uniq方法。这将删除任何重复的数组元素。

问题#2

else
x = "Unaccounted"
array.push( "#{x}: #{input.count(x)}")

您看不到"Unaccounted"元素的任何数量的原因是您添加了 * 单词 *(字符串)“Unaccounted”添加到数组中,但是您还重新定义了x。这里的问题是input实际上并不包含"Unaccounted"的任何示例,所以你的count总是0。我建议的解决方法是简单地查找inputgrading之间的长度差,这将告诉您"Unaccounted"元素的确切数量实际上是有的。

问题#3??

我假设你的意思是包含一个换行符,而不是一个正斜杠(/)后面跟着一个文字“n”(n)。我建议的修复方法当然是使用一个适当的换行符(\n)。如果我的假设是不正确的,忽略这一部分。
在所有更改之后,您的 * 最小 * 修改代码将如下所示:

def report_checker(string)

array = []
  grading = ["Green", "Amber", "Red"]

    input = string.tr(',', ' ').split(" ")
  
    input.each do |x|
       if grading.include?(x)
        array.push( "#{x}: #{input.count(x)}")
       else
        array.push( "Unaccounted: #{(input-grading).length}")
       end
    end   
    
    array.uniq.join("\n")
end

report_checker("Green, Amber, Green, Yellow, Blue, Blue")
#=> 
Green: 2
Amber: 1
Unaccounted: 3

再次声明,我并不是说这是最有效的方法,我只是给你一些小的修正,这样你就可以在需要的时候迈出第一步。

相关问题