供应Ruby数组Select一个动态块
Supply Ruby Array Select A Dynamic 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"}]
我知道像这样 select:
results = @network.select { |x| x["campaign"] == "Art Education" && x["status"] == "Open" }
过滤数组返回哈希数组,其中 selected 键具有搜索值。
但是,用户必须能够根据任何或所有具有用户提交的值的键来过滤此数组。
虽然我可以像这样将表单参数中的值替换到块中:
results = @network.select { |x| x[params[1]["column"]] == params[1]["search"] && x[params[2]["column"]] == params[2]["search"] }
每个 select 的逻辑可能不同。可能有多达 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
现在效果很好。
这是一种可能的方法。
让我们定义 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"}
现在,我们将选择此已处理的参数哈希 pm
中存在的键,并使用它从 @network
数组中获取每个元素的切片,如果已处理的参数哈希和切片哈希值相等,那么,我们就有了一个匹配项,我们可以 select 该项目。
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]}}
我有一个哈希数组。以下是典型值的一小部分示例:
[{"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"}]
我知道像这样 select:
results = @network.select { |x| x["campaign"] == "Art Education" && x["status"] == "Open" }
过滤数组返回哈希数组,其中 selected 键具有搜索值。
但是,用户必须能够根据任何或所有具有用户提交的值的键来过滤此数组。
虽然我可以像这样将表单参数中的值替换到块中:
results = @network.select { |x| x[params[1]["column"]] == params[1]["search"] && x[params[2]["column"]] == params[2]["search"] }
每个 select 的逻辑可能不同。可能有多达 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
现在效果很好。
这是一种可能的方法。
让我们定义 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"}
现在,我们将选择此已处理的参数哈希 pm
中存在的键,并使用它从 @network
数组中获取每个元素的切片,如果已处理的参数哈希和切片哈希值相等,那么,我们就有了一个匹配项,我们可以 select 该项目。
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]}}