在ruby中执行多项测试的最惯用方法是什么?

时间:2014-08-29 23:42:21

标签: ruby

我有以下逻辑:

some_array.each do |element|
  if element[:apples] == another_hash[:apples] &&
    element[:oranges] == another_hash[:oranges] &&
    element[:pineapple] == another_hash[:pineapple]
      match = element
     break
  end
end

我遍历键值对列表。如果我可以匹配所需的键(3/5),那么我将元素放在var中供以后使用。如果我找到一个匹配,我就会摆脱循环。

我正在寻找最优化这种条件的惯用方法。提前谢谢。

4 个答案:

答案 0 :(得分:4)

怎么样:

match = some_array.find do |element|
  [:apples, :oranges, :pinapple].all? {|key| element[key] == another_hash[key]}
end

如果您想从5个键中选择任何至少有3个匹配键的元素,那么:

match = some_array.find do |element|
  element.keys.select {|key| element[key| == another_hash[key]}.size > 2
end 

答案 1 :(得分:3)

我就是这样做的。

<强>代码

def fruit_match(some_array, another_hash, fruit)
  other_vals = another_hash.values_at(*fruit)
  return nil if other_vals.include?(nil)
  some_array.find { |h| h.values_at(*fruit) == other_vals }
end

<强>实施例

some_array = [ { apple: 1, orange: 2, pineapple: 3, plum: 4 },
               { apple: 1, cherry: 7, pineapple: 6, plum: 2 },
               { apple: 6, cherry: 2, pineapple: 8, fig:  3 } ]

another_hash = { apple: 6, cherry: 4, pineapple: 8, quamquat: 5 }

fruit = [:apple, :pineapple]
fruit_match(some_array, another_hash, fruit)
  #=> { :apple=>6, :cherry=>2, :pineapple=>8, :fig=>3 }

fruit = [:apple, :plum]
fruit_match(some_array, another_hash, fruit)
  #=> nil

[编辑:我没注意到&#34; 3-5&#34;比赛直到我看到@ 7stud的回答。要求匹配数量落在给定范围内是一个有趣的变化。以下是我如何解决这一要求。

<强>代码

def fruit_match(some_array, another_hash, fruit, limits)
  other_vals = another_hash.values_at(*fruit)
  some_array.select { |h| limits.cover?(h.values_at(*fruit)
                                .zip(other_vals)
                                .count {|e,o| e==o && e}) }
end

示例

some_array = [ { apple: 1, orange: 2, pineapple: 1, cherry: 1 },
               { apple: 2, cherry: 7, pineapple: 6, plum: 2 },
               { apple: 6, cherry: 1, pineapple: 8, fig:  3 },
               { apple: 1, banana: 2, pineapple: 1, fig:  3 } ]

another_hash = { apple: 1, cherry: 1, pineapple: 1, quamquat: 1 }
fruit = [:apple, :pineapple, :cherry]
limits = (1..2)

fruit_match(some_array, another_hash, fruit, limits)
  #=> [{:apple=>6, :cherry=>1, :pineapple=>8, :fig=>3},
  #    {:apple=>1, :banana=>2, :pineapple=>1, :fig=>3}]

<强>潮]

答案 2 :(得分:1)

我认为更可读的版本是slice

keys = [:apples, :oranges, :pinapple]
match = some_array.find {|e| e.slice( *keys ) == another_hash.slice( *keys )}

<强>更新

Slice不是Hash的纯ruby方法,它包含在Rails的ActiveSupport库中。

如果您不想使用Rails,只需加载Active Support即可。

将active_support添加到您的Gemfile和require "active_support/core_ext/hash/slice"

或者您可以将slice.rb的内容粘贴到您的应用中。可以找到该网址here

答案 3 :(得分:1)

  

如果我可以匹配所需的键(3/5)

我认为任何公布的答案都不会解决这个问题。

target_keys = %i[
  apples
  oranges
  pineapples
  strawberries
  bananas
]

data = [
  {beer: 0, apples: 1, oranges: 2, pineapples: 3, strawberries: 4, bananas: 5},
  {beer: 1, apples: 6, oranges: 7, pineapples: 8, strawberries: 9, bananas: 10},
  {beer: 2, apples: 6, oranges: 2, pineapples: 3, strawberries: 9, bananas: 10},
]

match_hash = {
  apples: 6, oranges: 2, pineapples: 3, strawberries: 9, bananas: 10
}

required_matches = 3
required_values = match_hash.values_at(*target_keys).to_enum
found_match = nil

catch :done do

  data.each do |hash|
    found_values = hash.values_at(*target_keys).to_enum
    match_count = 0

    loop do
      match_count += 1 if found_values.next == required_values.next

      if match_count == required_matches
        found_match = hash
        throw :done
      end
    end

    required_values.rewind
  end

end

p found_match

--output:--
{:beer=>1, :apples=>6, :oranges=>7, :pineapple=>8, :strawberry=>9, :banana=>10