2017-11-10 241 views
0

我需要過濾嵌套散列以返回特定屬性組合的項目。如果該屬性存在,則返回該散列,如果該屬性不存在,則返回默認值。如果該屬性設置爲「無」,則不返回任何內容。請看下面的哈希:ruby​​從嵌套散列選擇內部散列

{ 
    "size"=>{ 
    "default"=>{ 
     "jeans"=>"boyfriend" 
    }, 
    "blue"=>"none" 
}, 
"style"=>{ 
    "default"=>{ 
    "shoes"=>"boots" 
    }, 
    "blue"=>{ 
    "jeans"=>"jeggings" 
    } 
    } 
} 

如果顏色是 '黑',然後

{ 
    "size"=>{ 
    "jeans"=>"boyfriend" 
    }, 
    "style"=>{ 
    "shoes"=>"boots" 
    } 
} 

,或者如果顏色是 '藍色',然後

{ 
    "size"=>{ 
    }, 
    "style"=>{ 
    "jeans"=>"jeggings" 
    } 
} 

什麼是最好的方法做這個?我嘗試過各種組合的選擇和刪除,但最終與一個數組或包含顏色鍵的散列。

+0

你能提供一個你的代碼樣本嗎? – JMichelB

+1

你遇到什麼問題?你的代碼有什麼問題?你有錯誤信息嗎?什麼是錯誤信息?你得到的結果不是你期待的結果嗎?你期望得到什麼結果?爲什麼?你得到的結果是什麼?兩者有什麼不同?你正在觀察的行爲不是所期望的行爲?什麼是期望的行爲,爲什麼,觀察到的行爲是什麼,以及它們以何種方式不同?請提供[mcve]。 –

+0

「做這件事的最好方法是什麼?」 - 你通過編寫這樣做的程序來做到這一點。如果您的程序有問題,請仔細閱讀您正在使用的所有方法,類,模塊和庫的文檔,爲您的程序編寫測試,使用筆和紙記錄執行情況,單步執行調試程序,然後在上面睡覺,從頭開始,再次睡上,然後*然後只有這樣*問一個關於[so]的重點狹窄的問題。 –

回答

0

假設h是問題中給出的散列,如果我對問題的理解是正確的,則以下方法將返回所需的散列。

def doit(h, color) 
    h.each_with_object({}) do |(k,f),g| 
    c,v = f.find { |kk,_| kk != "default" } 
    if c == color 
     g[k] = v.is_a?(Hash) ? v : {} 
    else 
     g[k] = f["default"] 
    end 
    end 
end 

doit(h, 'black') 
    #=> {"size"=>{"jeans"=>"boyfriend"}, "style"=>{"shoes"=>"boots"}} 
doit(h, 'blue') 
    #=> {"size"=>{}, "style"=>{"jeans"=>"jeggings"}} 

第二個例子的步驟如下。

color = 'blue' 

enum = h.each_with_object({}) 
    #=> #<Enumerator: {"size"=>{"default"=>{"jeans"=>"boyfriend"}, 
    #  "blue"=>"none"}, "style"=>{"default"=>{"shoes"=>"boots"}, 
    #  "blue"=>{"jeans"=>"jeggings"}}}:each_with_object({})> 

此枚舉的第一值時產生:

x = enum.next 
    #=> [["size", {"default"=>{"jeans"=>"boyfriend"}, "blue"=>"none"}], {}] 

並傳遞給該塊。塊變量被設置等於x和它們的值通過「消歧」確定:

(k,f),g = x 
k #=> "size" 
f ##=> {"default"=>{"jeans"=>"boyfriend"}, "blue"=>"none"} 
g #=> {} 

現在執行的塊的計算。

c,v = f.find { |kk,_| kk != "default" } 
    #=> ["blue", "none"] 
C#=> "blue" 
v #=> "none" 

由於

c == color 
    #=> "blue" == "blue" => true 

我們計算

v.is_a?(Hash) 
    #=> false 

,因此執行任務

g[k] = {} 
    #=> {} 

以至於現在

g #=> {"size"=>{}} 

h的第二個也是最後一個元素現在生成並傳遞給該塊。

x = enum.next 
    #=> [["style", {"default"=>{"shoes"=>"boots"}, 
    #  "blue"=>{"jeans"=>"jeggings"}}], {"style"=>{"jeans"=>"jeggings"}}] 
(k,f),g = x 
k #=> "style" 
f #=> {"default"=>{"shoes"=>"boots"}, "blue"=>{"jeans"=>"jeggings"}} 
g #=> {"size"=>"none"} 
c,v = f.find { |kk,_| kk != "default" } 
    #=> ["blue", {"jeans"=>"jeggings"}] 
C#=> "blue" 
v #=> {"jeans"=>"jeggings"} 
c == color 
    # "blue" == "blue" => true 
v.is_a?(Hash) 
    #=> true 
g[k] = v 
    #=> {"jeans"=>"jeggings"} 
g #=> {"size"=>"none", "style"=>{"jeans"=>"jeggings"}} 

g被返回。

+0

感謝您使用each_with_object的詳細解釋和一個不錯的方法。我會試驗一下。 – margo

0

下面是我經過一些重構後得到的結果。它的工作和測試全部通過。可以做更多的重構。

class Filterer 
    def self.filter(facets, color) 
    acc = {} 
    facets.each do |k, facets| 
     facets.each do |_, facet| 
     acc[k] = color_facets(color, facets) 
     end 
    end 

    acc 
    end 

    def self.color_facets(color, facets) 
    return {} if no_facets?(color, facets) 

    facets[color] ? facets[color] : facets['default'] 
    end 

    def self.no_facets?(color, facets) 
    facets[color] && facets[color] == 'no facet' 
    end 
end