2014-08-29 75 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

相關問題