当试图找到“奇妙”字母的频率时,我无法理解给定的解决方案:
def letter_count(str)
counts = {}
str.each_char do |char|
next if char == " "
counts[char] = 0 unless counts.include?(char)
counts[char] += 1
end
counts
end
我尝试解构它,当我创建下面的代码时,我希望它能完成同样的事情。然而,它给了我不同的结果。
blah = {}
x = 'fantastic'
x.each_char do |char|
next if char == " "
blah[char] = 0
unless
blah.include?(char)
blah[char] += 1
end
blah
end
第一段代码给出了以下内容
puts letter_count('fantastic')
>
{"f"=>1, "a"=>2, "n"=>1, "t"=>2, "s"=>1, "i"=>1, "c"=>1}
为什么第二段代码会给我
puts blah
>
{"f"=>0, "a"=>0, "n"=>0, "t"=>0, "s"=>0, "i"=>0, "c"=>0}
有人可以分解代码并告诉我底层的区别是什么。我想一旦我理解了这一点,我就能真正理解第一段代码。另外,如果你想解释一下第一段代码,以帮助我,那也很棒。
答案 0 :(得分:2)
你不能拆分这条线......
counts[char] = 0 unless counts.include?(char)
...按照你做的方式多行。尾随条件仅适用于一行。
如果您想将其拆分为多行,则必须转换为传统的if / end(在本例中为unless / end)格式。
unless counts.include?(char)
counts[char] = 0
end
以下是代码的解释......
# we define a method letter_count that accepts one argument str
def letter_count(str)
# we create an empty hash
counts = {}
# we loop through all the characters in the string... we will refer to each character as char
str.each_char do |char|
# we skip blank characters (we go and process the next character)
next if char == " "
# if there is no hash entry for the current character we initialis the
# count for that character to zero
counts[char] = 0 unless counts.include?(char)
# we increase the count for the current character by 1
counts[char] += 1
# we end the each_char loop
end
# we make sure the hash of counts is returned at the end of this method
counts
# end of the method
end
答案 1 :(得分:2)
既然@Steve已经回答了你的问题并且你接受了他的答案,也许我可以建议另一种方法来计算这些字母。这只是可以采取的众多方法之一。
<强>代码强>
def letter_count(str)
str.downcase.each_char.with_object({}) { |c,h|
(h[c] = h.fetch(c,0) + 1) if c =~ /[a-z]/ }
end
示例强>
letter_count('Fantastic')
#=> {"f"=>1, "a"=>2, "n"=>1, "t"=>2, "s"=>1, "i"=>1, "c"=>1}
<强>解释强>
以下是发生的事情。
str = 'Fantastic'
我们使用String#downcase,例如,为了计算,'f'
和'F'
被视为相同的字符。 (如果您不想这样,只需删除.downcase
。)让
s = str.downcase #=> "fantastic"
在
s.each_char.with_object({}) { |c,h| (h[c] = h.fetch(c,0) + 1) c =~ /[a-z]/ }
枚举器String#each_char被链接到Enumerator#with_index。这将创建一个复合枚举器:
enum = s.each_char.with_object({})
#=> #<Enumerator: #<Enumerator: "fantastic":each_char>:with_object({})>
我们可以通过将枚举器转换为数组来查看枚举器将传递给块的内容:
enum.to_a
#=> [["f", {}], ["a", {}], ["n", {}], ["t", {}], ["a", {}],
# ["s", {}], ["t", {}], ["i", {}], ["c", {}]]
(实际上,它只传递带有'f'
的空哈希;此后它传递更新的哈希值。)枚举器with_object
创建一个由块变量{{1}表示的空哈希}。
传递给块的第一个元素h
是字符串enum
。块变量'f'
被赋值为该值,因此块中的表达式为:
c
评估为:
(h[c] = h.fetch(c,0) + 1) if c =~ /[a-z]/
现在
(h['f'] = h.fetch('f',0) + 1) if 'f' =~ /[a-z]/
当且仅当c =~ /[a-z]/
是小写字母时,才是true
。这里
c
所以我们评估表达式
'f' =~ /[a-z]/ #=> true
如果h[c] = h.fetch(c,0) + 1
有密钥h.fetch(c,0)
,则 h[c]
会返回h
;否则它返回Hash#fetch的第二个参数的值,此处为零。 (c
也可以阻止。)
由于fetch
现在为空,它变为
h
然后,枚举器h['f'] = 0 + 1 #=> 1
会将each_char
,'a'
和'n'
传递给该块,从而导致哈希变为
't'
传入的下一个字符是第二个h = {'f'=>1, 'a'=>1, 'n'=>1, 't'=>1 }
。由于'a'
已有密钥h
,
'a'
评估为
h[c] = h.fetch(c,0) + 1
字符串的其余部分以相同的方式处理。