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

設定した行はhash[letter] = 1常に実行されます。これが、ハッシュの各文字の値が 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 に答える
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の代わりに使用gsubsplit

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 に答える
2

この特定の問題は、適切なアルゴリズムを選択する方法の良い例ですが、さらに重要なのは、適切なデータ構造がソリューションを大幅に簡素化できることです。実際、この特定のケースでは、適切なデータ構造を選択すると、アルゴリズムが非常に単純になり、基本的に完全に消えてしまいます。データ構造すでに答えです。

私が話しているデータ構造は aMultisetです: aMultisetは a に似てSetいますが、一意のアイテムだけを保存するのではなく、アイテムを複数回追加できMultiSet、アイテムが追加された頻度をカウントします。これはまさにあなたがしたい。基本的に、Setは、特定のアイテムが にあるかどうかを示しSet ますMultiset。さらに、は、その特定のアイテムが にある頻度Multisetも示します。

残念ながらMultisetRubyのコアライブラリや標準ライブラリには実装がありませんが、gemがあります。

コード全体は文字通り次のとおりです。

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

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

はい、それだけです。それがコード全体です。ご覧のとおり、文字 が 1 回、文字'm'が 2 回、文字'o'が 1 回出現してい'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 に答える