简体   繁体   English

ruby重构class方法

[英]ruby refactoring class method

I am new to ruby. I am trying to create a report_checker function that checks how often the word "green, red, amber" appears and returns it in the format: "Green: 2/nAmber: 1/nRed:1".我是 ruby 的新手。我正在尝试创建一个 report_checker function,它检查单词“green, red, amber”出现的频率,并以以下格式返回它:“Green: 2/nAmber: 1/nRed:1”。

If the word is not one of the free mentioned, it is replaced with the word 'unaccounted' but the number of times it appears is still counted.如果该词不是自由提到的词之一,它将被替换为“unaccounted”,但它出现的次数仍然被计算在内。

My code is returning repeats eg if I give it the input report_checker("Green, Amber, Green").我的代码返回重复,例如,如果我给它输入 report_checker("Green, Amber, Green")。 It returns "Green: 2/nAmber: 1/nGreen: 2" as opposed to "Green: 2/nAmber: 1".它返回“Green: 2/nAmber: 1/nGreen: 2”而不是“Green: 2/nAmber: 1”。

Also, it doesn't count the number of times an unaccounted word appears.此外,它不计算未说明的单词出现的次数。 Any guidance on where I am going wrong?关于我哪里出错的任何指导?

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")

I tried pushing the words into separate words and returning the expected word with its count我尝试将单词推入单独的单词并返回预期的单词及其计数

There's a lot of things you can do here to steer this into more idiomatic Ruby:您可以在这里做很多事情来将其引导到更惯用的 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")

One thing you'll come to learn about Ruby is that simple mappings like this translate into very simple Ruby code.关于 Ruby,您将了解到的一件事是像这样的简单映射可以转换为非常简单的 Ruby 代码。 This might look a bit daunting now if you're not used to it, but keep in mind each component of that transformation isn't that complex, and further, that you can run up to that point to see what's going on, or even use .tap { |v| pv }.如果您不习惯,这现在看起来可能有点令人生畏,但请记住,该转换的每个组件都没有那么复杂,而且,您可以跑到那个点看看发生了什么,甚至使用.tap { |v| pv }. .tap { |v| pv }. in the middle to expand on what's flowing through there.在中间以扩展流经那里的内容。

Taking this further into the Ruby realm, you'd probably want to use symbols, as in :green and :amber , as these are very tidy as things like Hash keys: { green: 0, amber: 2 } etc.进一步考虑 Ruby realm,您可能想要使用符号,如:green:amber ,因为它们非常整洁,例如 Hash keys: { green: 0, amber: 2 }等。

While this is done as a single method, it might make sense to split this into two concerns: One focused on computing the report itself, as in to a form like { green: 2, amber: 1, unaccounted: 1 } and a second that can convert reports of that form into the desired output string.虽然这是作为单一方法完成的,但将其分为两个关注点可能是有意义的:一个关注于计算报告本身,如{ green: 2, amber: 1, unaccounted: 1 }和第二个可以将该表单的报告转换为所需的 output 字符串。

There are lots and lots of ways to accomplish your end goal in Ruby. I won't go over those, but I will take a moment to point out a few key issues with your code in order to show you where the most notable probelms are and to show you how to fix it with as few changes as I can personally think of:有很多方法可以实现 Ruby 中的最终目标。我不会 go 超过这些,但我会花点时间指出您的代码的几个关键问题,以便向您展示最值得注意的问题在哪里并向您展示如何用我个人能想到的尽可能少的更改来修复它:


Issue #1:问题#1:

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

This results in a new array element being added each and every time grading includes x .这会导致每次grading包括x时都会添加一个新的array元素。 This explains why you are getting repeated array elements ( "Green: 2/nAmber: 1/nGreen: 2" ).这解释了为什么你会得到重复的数组元素( "Green: 2/nAmber: 1/nGreen: 2" )。 My suggested fix for this issue is to use the uniq method in the last line of your method defintion.我建议的解决此问题的方法是在方法定义的最后一行使用uniq方法。 This will remove any duplicated array elements.这将删除任何重复的数组元素。


Issue #2问题 #2

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

The reason you're not seeing any quantity for your "Unaccounted" elements is that you're adding the word (string) "Unaccounted" to your array, but you've also re-defined x.您没有看到"Unaccounted"元素有任何数量的原因是您在数组中添加了单词(字符串)“Unaccounted”,但您还重新定义了 x。 The problem here is that input does not actually include any instances of "Unaccounted" , so your count is always going to be 0 .这里的问题是input实际上不包含任何"Unaccounted"实例,因此您的count始终为0 My suggested fix for this is to simply find the length difference between input and grading which will tell you exactly how many "Unaccounted" elements there actually are.我建议的解决方法是简单地找到inputgrading之间的长度差异,这将告诉您实际有多少"Unaccounted"元素。


Issue #3??问题#3??

I'm assuming you meant to include a newline and not a forward slash ( / ) followed by a literal "n" ( n ).我假设您打算包含换行符而不是正斜杠 ( / ) 后跟文字“n” ( n )。 My suggested fix for this of course is to use a proper newline ( \n ).我建议的解决方法当然是使用适当的换行符 ( \n )。 If my assumption is incorrect, just ignore that part.如果我的假设不正确,请忽略该部分。


After all changes, your minimally modified code would look like this:在所有更改之后,您的最小修改代码将如下所示:

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

Again, I'm not suggesting that this is the most effective or efficient approach.同样,我并不是说这是最有效或最高效的方法。 I'm just giving you some minor corrections to work with so you can take baby steps if so desired.我只是给你一些小的更正,以便你可以根据需要采取一些小步骤。

Try with blow code尝试打击代码

add your display logic outside of method在方法之外添加显示逻辑

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}"}

Output Output

Green : 2
Amber : 1
Unaccounted : 2

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM