迭代Ruby Hashes数组并计算no。时代价值出现了吗?

时间:2015-01-20 16:58:52

标签: ruby-on-rails ruby arrays hash

我有一个带结构的Hashes Ruby数组

[{:fruit=>"apple"}, {:fruit=>"apple"}, {:fruit=>"apple"}, {:fruit=>"banana"}, {:fruit=>"banana"}, {:fruit=>"pineapple"}].

我想要一个最终的哈希值:

{:apple => 3,:banana=> 2,:pineapple=>1}

如何做到这一点?

3 个答案:

答案 0 :(得分:2)

创建一个具有默认值的哈希并迭代数组中的每个哈希:

fruits = [{:fruit=>"apple"}, {:fruit=>"apple"}, {:fruit=>"apple"}, {:fruit=>"banana"}, {:fruit=>"banana"}, {:fruit=>"pineapple"}]
h = Hash.new(0)
fruits.each { |item| h[item[:fruit]] += 1 }

答案 1 :(得分:2)

计算这样的直方图的常用技巧是使用Enumerable#group_by然后Enumerable#map生成的Arraysize s,最后转换为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>>

答案 2 :(得分:2)

@Simone说得对,你可以使用inject方法计算出现次数,如下所示:

[23] pry(main)> arr
=> [{:fruit=>"apple"}, {:fruit=>"apple"}, {:fruit=>"apple"}, {:fruit=>"banana"}, {:fruit=>"banana"}, {:fruit=>"pineapple"}]
[24] pry(main)> arr.inject({}) { |sum, val| sum[val[:fruit]] = sum[val[:fruit]].to_i + 1; sum }
=> {"apple"=>3, "banana"=>2, "pineapple"=>1} 

这在代码中并不是很明确,但你需要在哈希上调用.to_i的原因是因为如果它返回nil(即第一次遇到“apple”),你就不能执行nil + 1,因此nil.to_i变为零。我不认为上面的代码是非常清晰的,所以我想我会提到它。

虽然我的是一个“解决方案”,但Jorg在最佳实践方面做得恰到好处,这将是一个了解OO解决方案的好机会。