2017-11-10 243 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