我想写一个函数来计算str中所有字母的出现次数,听起来很容易,我想出了这个
def letter_count(str)
hash = {}
letters = str.gsub(' ','').split('')
letters.each do |letter|
if hash.include?(letter)
hash[letter] += 1
else
hash[letter] = 1
end
end
hash
end
letter_count('moon') => {"m"=>1, "o"=>2, "n"=>1}
当我试图将其缩短为
时def letter_count(str)
hash = {}
letters = str.gsub(' ','').split('')
letters.each do |letter|
hash[letter] += 1 if hash.include?(letter)
hash[letter] = 1
end
hash
end
答案变成了:
letter_count('moon') => {"m"=>1, "o"=>1, "n"=>1}
你可以告诉我我错了吗???谢谢!!!!!!!
答案 0 :(得分:4)
我的个人实施(只是为了好玩):
str = "moon"
counts = Hash[ str.scan(/\S/).group_by(&:chr).map{ |c,a| [c,a.length] } ]
#=> {"m"=>1, "o"=>2, "n"=>1}
答案 1 :(得分:3)
始终执行您设置hash[letter] = 1
的行。这就是为什么你的哈希值每个字母的值为1.你可以使用三元运算符将它变为一行,如下所示:
letters.each do |letter|
hash.include?(letter) ? hash[letter] += 1 : hash[letter] = 1
end
这是一个if,else then语句。如果散列将字母作为键,则值递增,否则散列将字母存储为键,并将“1”指定为其值。
一个有用的链接:http://alvinalexander.com/blog/post/ruby/examples-ruby-ternary-operator-true-false-syntax
答案 2 :(得分:3)
这个怎么样?
def letter_count(str)
str.gsub(' ','').split('').each_with_object(Hash.new(0)) do |letter, hash|
hash[letter] += 1
end
end
letter_count('moon') # => {"m"=>1, "o"=>2, "n"=>1}
稍作改进:使用scan
代替gsub
+ split
def letter_count(str)
str.scan(/[^\s]/).each_with_object(Hash.new(0)) do |letter, hash|
hash[letter] += 1
end
end
letter_count('sun and stars') # => {"s"=>3, "u"=>1, "n"=>2, "a"=>2, "d"=>1, "t"=>1, "r"=>1}
答案 3 :(得分:2)
这个特殊问题是选择正确算法的一个很好的例子,但更重要的是,正确的数据结构可以大规模简化解决方案。事实上,在这种特殊情况下,选择正确的数据结构会使算法变得微不足道,以至于它基本上完全消失了:数据结构已经 答案。
我所说的数据结构是Multiset
:Multiset
就像Set
,除了它不存储唯一的项目,而是可以添加多个项目时间和MultiSet
将统计项目的添加频率 - 这正是您想要的。基本上,Set
会告诉您特定项目是否在Set
中,Multiset
此外还会告诉您多久一次该特定项目位于Multiset
。
不幸的是,Ruby核心库或标准库中没有Multiset
实现,但有is a gem。
整个代码只是:
def letter_count(str)
Multiset[*str.chars]
end
letter_count('moon')
# => #<Multiset:#1 "m", #2 "o", #1 "n">
是的,就是这样。这就是整个代码。如您所见,有一次出现'm'
字母,两次出现字母'o'
,另一次出现字母'n'
。
答案 4 :(得分:1)
hash[letter] = 1
将始终执行。您可以像这样重构代码:
letters.each do |letter|
hash[letter] = 0 unless hash[letter]
hash[letter] += 1
end
或没有后缀条件:
letters.each do |letter|
if hash[letter]
hash[letter] += 1
else
hash[letter] = 1
end
end
答案 5 :(得分:0)
如前所述,问题是因为hash[letter] = 1
总是被执行。
为了使你的代码更短,你可以通过将默认值传递给你的哈希构造函数来完全摆脱if
:
hash = Hash.new(0)
letters.each { |letter| hash[letter] += 1 }