使用Hash.new作为数组缩减的初始值

6

我有一个类似于以下的数组

[1,1,2,3,3,3,4,5,5]

我想要统计每个数字出现的次数,尝试以下代码:

[1,1,2,3,3,3,4,5,5].reduce(Hash.new(0)) { |hash,number| hash[number] += 1 }

问题是当我尝试运行它时,会出现以下错误。
NoMethodError: undefined method `[]=' for 1:Fixnum
    from (irb):6:in `block in irb_binding'
    from (irb):6:in `each'
    from (irb):6:in `reduce'
    from (irb):6

我能否像这样设置初始值,或者我理解错了吗?
5个回答

8

您可以使用each_with_object来获得更简洁的语法。

[1,1,2,3,3,3,4,5,5].each_with_object(Hash.new(0)) { |number, hash| hash[number] += 1 }

请注意参数的顺序是相反的,即|数字,哈希值|

我总是忘记有 each_with_object 这个方法。我觉得它比在每次迭代中返回哈希表更加简洁。 - Konrad Reiche

6

你可以使用 reduce,但如果你想这样做,你必须再次返回哈希表:

[1,1,2,3,3,3,4,5,5].reduce(Hash.new(0)) do |hash,number|
  hash[number] += 1 
  hash
end

如果没有进行赋值操作,将会返回 hash[number] 的值。哈希表赋值后的值就是其本身。该区块构建在您之前返回的值的基础上。

这意味着,在第一次之后,它会尝试像这样操作:1[1] += 1,但这当然不起作用,因为Fixnum没有实现方法[] =


5

我喜欢使用reducehash.update。它返回数组,我不需要; hash部分:

[1,1,2,3,3,3,4,5,5].reduce(Hash.new(0)) { |h, n| h.update(n => h[n].next) }

1
不错!我之前不熟悉update,现在已经掌握了。(读者请注意,如果不明显的话,他也可以使用+1代替next)。 - Cary Swoveland

2

您的问题已得到解答,但这里还有另一种解决方法:

[编辑以采用@David的建议。]

a = [1,1,2,3,3,3,4,5,5]
Hash[a.group_by(&:to_i).map {|g| [g.first, g.last.size]}]

这也是可行的:

a.group_by{|e| e}.inject({}) {|h, (k,v)| h[k] = v.size; h}

通过采用@spickermann的update(或其同义词merge!)可以改进它,以消除末尾烦人的; h

a.group_by{|e| e}.inject({}) {|h, (k,v)| h.merge!(k => v.size)}

过去,我有:

Hash[*a.group_by(&:to_i).to_a.map {|g| [g.first, g.last.size]}.flatten]

我不喜欢这里的 to_i。 我想使用 to_proc 替代 ...group_by {|x| x|}(如上面某个解决方案中所使用的),并且正在寻找一个返回接收器或其值的方法 mto_i 是我能做到的最好的方法(例如,2.to_i => 2),但只适用于整数。 有人能建议一种方法,针对广泛对象范围内使用 to_proc 的目的明显吗?


有点过于复杂了 ;) 你可以将代码简化为 Hash[a.group_by(&:to_i).map {|g| [g.first, g.last.size]}]。由于 Hash 继承了 Enumerablemap 方法,因此不必将其转换为 Array。此外,您可以避免展平结果数组和使用展开运算符。更不用说您可以在块参数中拆分 map 传递的对象了。我同意 Ruby 缺少返回自身的 .id 方法(被 Haskell 惯坏了 ;)) - David Unric

1
那很简单:
[1,1,2,3,3,3,4,5,5].group_by {|e| e}.collect {|k,v| [k,v.count]}
#=> [[1, 2], [2, 1], [3, 3], [4, 1], [5, 2]]

如果需要以哈希对象的形式返回结果。
Hash[[1,1,2,3,3,3,4,5,5].group_by {|e| e}.collect {|k,v| [k,v.count]}]
#=> {1=>2, 2=>1, 3=>3, 4=>1, 5=>2}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接