使用Ruby的句子中的字母数

aru*_*roy -3 ruby string

假设我有一个字符串"I am a good boy".我想要字符串中每个字母的总数.字母区分大小写.也就是说,Dd需要被视为两个不同的字符.

saw*_*awa 19

"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}
Run Code Online (Sandbox Code Playgroud)

  • @RubyLovely google for"inject(Hash.new(0))`; 这只是每个人计算频率的方式. (3认同)
  • +1我就是这样做的.这是直截了当的. (2认同)
  • 谁投票了?这个答案利用了reduce语句,效率更高. (2认同)
  • @RubyLovely您的代码确实有效,但效率不高.在字母'o'的第一次出现时,它扫描整个字符串,计算所有o,并将结果(3)存储在散列中.在第二个'o'它做同样的事情,等等. (2认同)
  • @RubyLovely:如果你要开始争论性能和效率,那么你应该用基准测试结果来支持它,否则它只是挥手. (2认同)

Dig*_*oss 14

a = "I am a good boy"

a.chars.group_by(&:chr).map { |k, v| [k, v.size] }
Run Code Online (Sandbox Code Playgroud)

  • @RubyLovely:你得到的结果(以不同的顺序)来自`a.chars.to_a.sort.group_by ...`.请离开电脑,再做一些其他的事情,你会因为所有这些不专业的行为而感到尴尬. (5认同)
  • @RubyLovely:我建议你自己尝试一下,仔细查看带有和不带`.to_a.sort`的结果.我还建议你在把自己挖到一个无法摆脱的洞之前放下铲子. (4认同)
  • "因为a.chars.group_by(&:chr).map {| k,v | [k,v.size]}我没有删除空格." 什么?!这与空间无关.`chars`是字符串中各个字符的迭代器.`group_by(&:chr)`按字符分组并返回一个散列,其中每个字符键的值都是相同字符出现的数组.`map`将每个哈希转换为字符和数组的大小.`to_a`不是必需的,但可能是习惯.`sort`是一种便利. (3认同)
  • @RubyLovely:哪个与"a.chars.to_a.sort.group_by ..."和"a.chars.group_by ..."之间没什么关系,这就是Tin Man在你之前试图告诉你的翻出来试图改变主题.我认为所有这些挖掘都会让你感到疲惫. (3认同)

und*_*gor 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
Run Code Online (Sandbox Code Playgroud)

给(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)
Run Code Online (Sandbox Code Playgroud)

有了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)
Run Code Online (Sandbox Code Playgroud)

所以对于非常短的字符串,RubyLovely解决方案的多次计数并没有受到伤害.实际上,它确实如此.


the*_*Man 6

我用的是:

str = "I am a good boy"
str.scan(/[[:alpha:]]/i).each_with_object(Hash.new(0)) { |c, h| h[c] += 1 }

哪个回报:

{
    "I" => 1,
    "a" => 2,
    "m" => 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,
    "a" => 2,
    "n" => 1,
    "ç" => 1,
    "i" => 1,
    "s" => 1
}