ruby从嵌套哈希中选择内部哈希

时间:2017-11-10 22:01:02

标签: ruby ruby-on-rails-4 hash

我需要过滤嵌套哈希以返回特定属性组合的项目。如果属性存在则返回该哈希,如果该属性不存在则返回默认值。如果该属性设置为“none”,则不返回任何内容。请考虑以下哈希:

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

如果颜色为“黑色”,那么

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

或者如果颜色是'蓝色',那么

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

最好的方法是什么?我已经尝试了select和delete的各种组合,但最终得到一个数组或包含颜色键的哈希。

2 个答案:

答案 0 :(得分: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,其值由&#34;消歧&#34;确定:

(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

答案 1 :(得分: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