供应Ruby数组选择动态块

时间:2016-01-22 18:54:54

标签: ruby-on-rails arrays ruby hash block

我有一系列哈希。以下是典型值的一小部分示例:

[{"id"=>1,
  "context"=>"r178",
  "asset"=>"Art Schools Hub",
  "campaign"=>"Fashion Careers",
  "contact_email"=>"evert_nolan@hammechaefer.net",
  "notes"=>"",
  "user_first_name"=>"Agustin",
  "user_last_name"=>"Welch",
  "status"=>"Completed",
  "date_collected"=>"01/22/16"},
 {"id"=>4,
  "context"=>"r178",
  "asset"=>"Art Schools Hub",
  "campaign"=>"Graphic Design Careers",
  "contact_email"=>"jamil_brakus@effertz.biz",
  "notes"=>"",
  "user_first_name"=>"Agustin",
  "user_last_name"=>"Welch",
  "status"=>"In Progress",
  "date_collected"=>"01/22/16"},
 {"id"=>15,
  "context"=>"r178",
  "asset"=>"Art Schools Hub",
  "campaign"=>"Art Education",
  "contact_email"=>"miss_kyle_mccullough@hicklezboncak.net",
  "notes"=>"",
  "user_first_name"=>"Jermaine",
  "user_last_name"=>"Wilkinson",
  "status"=>"Open",
  "date_collected"=>"01/22/16"}]

我知道做这样的选择:

results = @network.select { |x| x["campaign"] == "Art Education" && x["status"] == "Open" }

过滤数组,返回所选键具有搜索值的哈希数组。

但是,用户必须能够根据具有用户提交值的任何或所有密钥过滤此阵列。

虽然我可以将表单的参数中的值替换为块,如下所示:

results = @network.select { |x| x[params[1]["column"]] == params[1]["search"] && x[params[2]["column"]] == params[2]["search"] }

每个选择的逻辑可能不同。可能有多达10个不同的条件,其中列值和搜索值的形式为params。

我需要一种方法,根据用户提交的条件在select的块部分动态创建表达式。

不幸的是,我试图为块构造表达式的每种方法都会导致select无法评估的字符串值。

我已经做了好几天了,所以如果有人能帮我解决,我会非常感激。

修改 感谢Wand Maker优雅的解决方案,我根据他的代码进行了以下修改,允许用户根据搜索值以用户提交的值开头的键过滤哈希数组,而不是等于值:

pm = params.map { |h| {h["column"] => h["search"].downcase} }.reduce(&:merge)

result = @network.select do |h|
     temp = h.slice(*pm.keys)
     new_temp = Hash.new
     temp.each do |k,v|
          new_temp[k]=v.downcase.slice(0..pm[k].length - 1)
     end
     new_temp == pm
end

现在效果很好。

1 个答案:

答案 0 :(得分:2)

这是一种可能的方式。

让我们将params定义为:

params = [{"column" => "context", "search" => "r178"}, 
          {"column" => "campaign", "search" => "Art Education"}]

我们会将其处理为结构上类似于@network

的元素
pm = params.map { |h| {h["column"] => h["search"]} }.reduce(&:merge)
#=> {"context"=>"r178", "campaign"=>"Art Education"}

现在,我们将选择此处理的params散列pm中存在的密钥,并使用它来从@network数组中获取每个元素的切片,并且如果处理的params散列和切片散列都是等于,我们有匹配,我们可以选择项目。

result = @network.select {|h| h.slice(*pm.keys) == pm}

完整的代码示例,我添加了require "active_support/core_ext/hash",以便下面的程序可以作为独立的ruby程序运行以用于说明目的。在Rails代码中不需要它。

require "pp"
require "active_support/core_ext/hash"

@network = [{"id"=>1, "context"=>"r178", "asset"=>"Art Schools Hub", "campaign"=>"Fashion Careers", "contact_email"=>"evert_nolan@hammechaefer.net", "notes"=>"", "user_first_name"=>"Agustin", "user_last_name"=>"Welch", "status"=>"Completed", "date_collected"=>"01/22/16"},
{"id"=>4, "context"=>"r178", "asset"=>"Art Schools Hub", "campaign"=>"Graphic Design Careers", "contact_email"=>"jamil_brakus@effertz.biz", "notes"=>"", "user_first_name"=>"Agustin", "user_last_name"=>"Welch", "status"=>"In Progress", "date_collected"=>"01/22/16"},
{"id"=>15, "context"=>"r178", "asset"=>"Art Schools Hub", "campaign"=>"Art Education", "contact_email"=>"miss_kyle_mccullough@hicklezboncak.net", "notes"=>"", "user_first_name"=>"Jermaine", "user_last_name"=>"Wilkinson", "status"=>"Open", "date_collected"=>"01/22/16"}]

params = [{"column" => "context", "search" => "r178"}, 
          {"column" => "campaign", "search" => "Art Education"}]

pm = params.map { |h| {h["column"] => h["search"]} }.reduce(&:merge)
pp result = @network.select {|h| h.slice(*pm.keys) == pm}

#=> [{"id"=>15,
#     "context"=>"r178",
#     "asset"=>"Art Schools Hub",
#      ...
#     "status"=>"Open",
#     "date_collected"=>"01/22/16"}]

关于评论中所寻求的澄清,该解决方案也可以适用于starts_with类型的条件。可以使用:

pp result = @network.select {|h| pm.keys.all?{|k| h[k].starts_with? pm[k]}}