1

我想写一个函数来计算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}

你能告诉我我哪里出错了吗???谢谢!!!!!!!

4

6 回答 6

4

我个人的实现(只是为了好玩):

str = "moon"
counts = Hash[ str.scan(/\S/).group_by(&:chr).map{ |c,a| [c,a.length] } ]
#=> {"m"=>1, "o"=>2, "n"=>1} 
于 2013-06-03T22:45:55.180 回答
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}
于 2013-06-03T22:40:02.137 回答
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

于 2013-06-03T22:35:25.240 回答
2

这个特定问题是如何选择正确算法的一个很好的例子,但更重要的是正确的数据结构可以大大简化解决方案。事实上,在这种特殊情况下,选择正确的数据结构将使算法变得如此微不足道,以至于它基本上完全消失了:数据结构已经答案。

我正在谈论的数据结构是 a Multiset: aMultiset就像 a Set,除了它不只存储唯一的项目,而是可以多次添加一个项目,并且MultiSet会计算一个项目的添加频率——这正是你要。基本上,aSet告诉您某个特定项目是否在 中Set 此外,aMultiset还告诉您该特定项目在 中的频率Multiset

不幸的是,Ruby 核心库或标准库中没有Multiset实现,但有一个 gem

整个代码实际上就是:

def letter_count(str)
  Multiset[*str.chars]
end

letter_count('moon')
# => #<Multiset:#1 "m", #2 "o", #1 "n">

对,就是那样。这就是整个代码。如您所见,出现了一次 letter 'm',两次出现了 letter'o'和一次出现了 letter 'n'

于 2013-06-03T23:59:05.907 回答
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
于 2013-06-03T22:34:57.737 回答
0

如前所述,问题是因为hash[letter] = 1总是被执行。

if为了使您的代码更短,您可以通过将默认值传递给您的哈希构造函数来完全摆脱:

hash = Hash.new(0)
letters.each { |letter| hash[letter] += 1 }
于 2013-06-04T02:03:50.093 回答