供应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]}}