我有一系列哈希。以下是典型值的一小部分示例:
[{"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
现在效果很好。
答案 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]}}