2014-08-29 78 views
2

我有以下逻辑:在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

如何:

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 
+0

Freakin真棒。比以前好多了。谢谢! – user2152283 2014-08-30 00:06:07

+0

对于我的例子,用'fruit = [:apple,:plum]'返回'{:apple => 6,:cherry => 2,:pineapple => 8,:fig => 3}',但'another_hash '没有键':plum',所以它应该返回'nil'。 – 2014-08-30 04:59:35

+0

@CarySwoveland - 这两个哈希函数都没有':plum',所以它的工作方式与我的想法相符? :) – BroiSatse 2014-08-30 11:47:39

1

更可读的版本我能想到的是slice

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

UPDATE

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

如果你不想使用Rails,你可以加载Active Support。

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

或者您可以将slice.rb的内容粘贴到您的应用程序的某处。该URL可以被发现here

+0

这看起来也是一个很好的解决方案。感谢您的反馈。 – user2152283 2014-08-30 03:14:41

+0

猫,你的意思是'values_at'你有'切片'吗? Hash和Enumerable都没有'slice'方法。有了'values_at',这几乎就是我所拥有的,除了处理我在@ BroiSatse解决方案的评论中提到的问题。 – 2014-08-30 05:08:02

+0

@CarySwoveland感谢您的建议。我更新了我的答案。 – 2014-09-03 02:08:33

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 

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

代码

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}] 

潮]

+0

您使用了'#values_at' ..我试图给出相同的解决方案..我现在不会.. +1 .. :-) – 2014-08-30 04:56:22

+0

谢谢Cary的反馈。这对我来说也是一个有效的解决方案。我在这里有三个答案的用例,所以这绝对是最有帮助的。谢谢! – user2152283 2014-08-30 04:56:29

+0

**只是用select替换find **我看不出如何工作。 – 7stud 2014-08-30 16:15:10

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 
+0

谢谢7stud。这个答案也给了我一些想法。我很感激你花时间。 – user2152283 2014-08-30 05:22:13

+0

@ user2152283,我修改了一下我的答案。 – 7stud 2014-08-30 05:50:00

相关问题