计算此类直方图的常用技巧是使用Enumerable#group_by,然后使用Enumerable#map,将生成的Arrays 转换为sizes,最后转换为Hash:
ary = [{ fruit: 'apple' }, { fruit: 'apple' }, { fruit: 'apple' },
{ fruit: 'banana' }, { fruit: 'banana' }, { fruit: 'pineapple' }]
ary.
group_by {|h| h.values.first }.
map {|fruit, ary| [fruit.to_sym, ary.size]}.
to_h
# => { apple: 3, banana: 2, pineapple: 1 }
但是有一个更好的方法:一个名为 MultiSet 的数据结构完全可以满足您的需求。不幸的是,Ruby 核心库或 stdlib 中没有一个,但您可以找到一些浮动的实现:
Multiset[*ary.map {|el| el.values.first.to_sym}]
# => #<Multiset:#3 :apple, #2 :banana, #1 :pineapple>
然而,几乎总是当你有一个数据结构时,比如一个符号哈希数组到字符串或类似的东西,那里有一个对象想要出来。毕竟,Ruby 是一种面向对象的语言,而不是一种面向符号的哈希数组到字符串的语言。
class Fruit
attr_reader :name
def ==(other)
name == other.name
end
def eql?(other)
name.eql?(other.name)
end
def hash
name.hash
end
def to_s
name
end
def inspect
"#<Fruit: #{name}>"
end
private
attr_writer :name
def initialize(name)
self.name = name
end
end
Multiset[Fruit.new('apple'), Fruit.new('apple'), Fruit.new('apple'),
Fruit.new('banana'), Fruit.new('banana'), Fruit.new('pineapple')]
# => #<Multiset:#3 #<Fruit: apple>, #2 #<Fruit: banana>, #1 #<Fruit: pineapple>>