-4

假设我有一个字符串"I am a good boy"。我想要字符串中每个字母的总数。字母区分大小写。即,D并且d需要被视为两个不同的字符。

4

5 回答 5

20
"I am a good boy".scan(/\w/).inject(Hash.new(0)){|h, c| h[c] += 1; h}
# => {"I"=>1, "a"=>2, "m"=>1, "g"=>1, "o"=>3, "d"=>1, "b"=>1, "y"=>1}
于 2013-04-20T20:21:04.997 回答
15
a = "I am a good boy"

a.chars.group_by(&:chr).map { |k, v| [k, v.size] }
于 2013-04-20T20:42:13.400 回答
8

这并不是一个答案,只是对现有答案的补充。

因为讨论了性能,这里有一些数据。

require 'benchmark'

s0 = "I am a good boy"
s = s0 * 1
N = 10000

Benchmark.bm(20) do | x |
  x.report('sawa') do
    N.times { s.scan(/\w/).inject(Hash.new(0)){|h, c| h[c] += 1; h} }
  end

  x.report('digitalross') do 
    N.times { s.chars.to_a.sort.group_by(&:chr).map { |k, v| [k, v.size] } }
  end

  x.report("digitalross'") do 
    N.times { s.chars.group_by(&:chr).map { |k, v| [k, v.size] } }
  end

  x.report('rubylovely') do
    N.times { s.gsub(/\s/,'').chars.with_object({}) {|c,ob| ob[c] = s.count(c)} }
  end
end

给(ruby 1.9.3p392在我的机器上)

                           user     system      total        real
sawa                   0.600000   0.000000   0.600000 (  0.601734)
digitalross            0.790000   0.000000   0.790000 (  0.806674)
digitalross'           0.640000   0.010000   0.650000 (  0.651802)
rubylovely             0.570000   0.000000   0.570000 (  0.572501)

和我s = s0 * 1000得到N = 10

                           user     system      total        real
sawa                   0.340000   0.000000   0.340000 (  0.340617)
digitalross            0.380000   0.000000   0.380000 (  0.411393)
digitalross'           0.230000   0.010000   0.240000 (  0.243389)
rubylovely             6.530000   0.000000   6.530000 (  6.603198)

所以对于非常短的字符串,RubyLovely 的解决方案的多次计数并没有什么坏处。实际上,确实如此。

于 2013-04-20T23:49:17.823 回答
6

我会使用:

str = "我是个好孩子"
str.scan(/[[:alpha:]]/i).each_with_object(Hash.new(0)) { |c, h| h[c] += 1 }

返回:

{
    "我" => 1,
    “一” => 2,
    “米” => 1,
    "g" => 1,
    "o" => 3,
    "d" => 1,
    "b" => 1,
    "y" => 1
}

我更喜欢使用scan,因为它使用的正则表达式会立即确定允许计算哪些字符。如果输入字符串包含“我是个好孩子”。其他一些解决方案将失败,因为它们对输入字符串过于特定,并且每次遇到意外字符时都需要进行调整。我们知道输入很少那么枯燥,在现实世界中,这种代码将用于一般句子。忽略前面不需要的字符很重要。


'Français'.scan(/[[:alpha:]]/i).each_with_object(Hash.new(0)) { |c, h| h[c] += 1 }

返回:

{
    "F" => 1,
    "r" => 1,
    “一” => 2,
    "n" => 1,
    "ç" => 1,
    “我” => 1,
    "s" => 1
}
于 2013-04-20T22:04:17.083 回答
2

我认为拼写一段代码没有任何问题,因此任何 Ruby 程序员(包括新手)都很容易理解它。而且,我想绕过那个字符串。

所以,我喜欢这样:

s = "I am a good boy"

def count_word_characters(s)
    h = Hash.new(0)
    s.each_char do |char| 
        next unless char =~/\w/
        h[char] += 1
    end
    h
end

因为:

  • 很容易看出哈希 h 是如何创建、填充和输出的
  • 哈希 h 在输入字符串上填充一次
  • 很明显我们跳过了非单词字符
于 2013-04-21T08:58:19.937 回答