2

Ruby 哈希是否有类似的方法reject!返回匹配项并在哈希中只留下不匹配项?例如:

planets = {'Mars' => 2, 'Jupiter' => 63, 'Saturn' => 47}

few_moons = planets.some_method! do |planet, moon_count|
  moon_count < 50
end

few_moons #=> {'Mars'  => 2, 'Saturn' => 47}
planets   #=> {'Jupiter' => 63}

reject!返回原始哈希,减去被拒绝的项目。partition很接近,但它返回元组数组,而不是哈希,并且不修改原始哈希。

我在文档中看不到这样的东西,并且想在自己动手之前先问问。

4

5 回答 5

4

一种解决方法是使用 Proc 两次:

moon_filter = Proc.new {|planet, moon_count| moon_count < 50 }
few_moons   = planets.select(&moon_filter)
lotsa_moons = planets.reject(&moon_filter)
planets     = lotsa_moons
于 2012-04-17T20:08:09.253 回答
4
few_moons, many_moons = 
  planets.partition { |planet, moon_count| moon_count < 50 } \
  .map{ |v| Hash[v] }
于 2012-04-17T20:43:06.273 回答
2

还有Enumerable#group_by

planets_with = planets.group_by do |planet, moon_count|
  moon_count < 50 ? :many_moons : :few_moons
end

few  = planets_with[:few_moons]
many = planets_with[:many_moons]

但是,这将映射到数组数组而不是哈希数组。要解决这个问题:

planets_with.merge!(planets_with) { |key, values| Hash[values] }
于 2012-04-17T20:00:59.927 回答
1

我自己卷了

class Hash
  def reject_and_return!(&block)
    matches = {}
    self.each do |k, v|
      matches[k] = self.delete(k) if block.call(k, v)
    end
    matches
  end
end

按预期工作:

planets = {'Mars' => 2, 'Jupiter' => 63, 'Saturn' => 47}

few_moons = planets.reject_and_return! do |planet, moon_count|
  moon_count < 50
end

few_moons #=> {'Mars'  => 2, 'Saturn' => 47}
planets   #=> {'Jupiter' => 63}
于 2012-04-17T20:43:00.017 回答
0

Hash[] 构造函数将从分区中取回数组并按照您想要的方式将它们转换为散列。这不是一条线,但我认为它更干净:

a, not_a = {a: 'b', c: 'd', e: 'f'}.partition{|k,v| k == :a} a=Hash[a] not_a = Hash[not_a}

于 2012-11-05T20:56:40.920 回答