避免使用嵌套的选择块

时间:2015-01-05 05:47:07

标签: ruby

我必须从json文档中检索一些与电影和节目相关的信息。

unique_nos = js['navigation']['category'].select{|n|  n['name']=="Home"}.first['category'].select{|s| s['name']=="#{type}"}.first['category'].select{|k| k['name']=='Movie Studios'}.first['category'].map{|l| l['categoryId']}

电视节目也是如此。

unique_nos = js['navigation']['category'].select{|n|  n['name']=="Home"}.first['category'].select{|s| s['name']=='TV'}.first['category'].select{|k| k['name']=='Networks'}.first['category'].map{|l| l['categoryId']}

我想避免执行相同任务的重复代码。我宁愿将此块作为参数传递,因此它可能是动态的。有没有办法用元编程实现这个目标?

2 个答案:

答案 0 :(得分:2)

您可以将其简单地提取为一种方法:

def find_unique_nos(js, type, category)
  js['navigation']['category'].select{|n| n['name']=="Home"}.first['category'].select{|s| s['name']== type }.first['category'].select{|k| k['name']==category}.first['category'].map{|l| l['categoryId']}
end

在旁注中,select { ... }.first相当于find { ... },因此您可以将其简化为:

def find_unique_nos(js, type, category)
  js['navigation']['category'].find{|n| n['name'] == "Home" }['category']
                              .find{|s| s['name'] == type }['category']
                              .find{|k| k['name'] == category }['category']
                              .map{|l| l['categoryId']}
end

如果您想要更复杂,可以使用构建器来执行find{ ... }['category']的重复性工作:

def find_unique_nos(js, type, category)
  ['Home', type, category].inject(js['navigation']['category']) do |cat, name|
     cat.find{|n| n['name'] == name }['category']
  end.map{|l| l['categoryId']}
end

答案 1 :(得分:0)

请考虑使用中间变量来分解这些长链,这将有助于简化调试和理解。在重新格式化时使用相同的代码:

def unique_numbers(json: j, type: t)
  category = type == 'TV' ? 'Networks' : 'Movie Studios'
  json['navigation']['category']
    .select{|n| n['name']=="Home"}
    .first['category']
    .select{|s| s['name'] == type }
    .first['category']
    .select{|k| k['name'] == category }
    .first['category']
    .map{|l| l['categoryId']}
end