如何比较多维数组元素与哈希数组
How to compare multidimensional array element with array of hashes
我正在尝试对数据实施动态过滤器。我有过滤选项的多维数组:
filter_option = [["accountid", "<", "2"],["first_name", "=", "John"],["lastname", "=", "deo"]]
和哈希数组为:
reports = [{accountid: 1, first_name: "Elen", lastname: "Adam"},{accountid: 1, first_name: "niokie", lastname: "c"},{accountid: 2, first_name: "john", lastname: "deo"},{accountid: 4, first_name: "sherry", lastname: "b"},{accountid: 3, first_name: "Jimmy", lastname: "S"}]
所有过滤器选项元素应与 report
数组的每个散列相匹配。例如,在 filter_option
中,我们有 account_id < 2
、first_name = john
和 last_name = deo
。所以我需要那个满足所有这些过滤器的散列。
如果filter_option
是:
filter_option = [["accountid", ">", "2"]]
那么输出应该是:
filtered_report = [{accountid: 4, first_name: "sherry", lastname: "b"},{accountid: 3, first_name: "Jimmy", lastname: "S"}]
如果过滤器选项是:
filter_option = [["accountid", "=", "2"],["first_name","=","john"],["lastname","=","deo"]]
那么输出应该是:
filtered_report = [{accountid: 2, first_name: "john", lastname: "deo"}]
如果过滤器选项是:
filter_option = [["accountid", ">", "3"],["first_name","=","sherry"],["lastname","=","b"]]
那么输出应该是:
filtered_report = [{accountid: 4, first_name: "sherry", lastname: "b"}]
我没有得到我需要的解决方案。有谁知道获得我需要的输出的最佳解决方案是什么?
我写的代码如下:
filtered_report = []
filter_option.each do |f|
reports.each do |r|
r.each do |k,v|
if f[1] == "="
if f[0].to_sym == k && v == f[2]
filtered_report << r
end
elsif f[1] == ">"
if f[0].to_sym == k && v > f[2].to_i
filtered_report << r
end
elsif f[1] == "<"
if f[0].to_sym == k && v < f[2].to_i
filtered_report << r
end
end
end
end
end
当我执行这段代码时,我会得到如下输出:
filtered_report = [{:accountid=>1, :first_name=>"Elen", :lastname=>"Adam"}, {:accountid=>1, :first_name=>"Elen", :lastname=>"Adam"}, {:accountid=>2, :first_name=>"john", :lastname=>"deo"}, {:accountid=>2, :first_name=>"john", :lastname=>"deo"}]
这是不正确的,因为数组中没有一个散列满足 filter_option
数组中给定的所有过滤器,输出应该是 nil
.
您的代码实现了过滤器选项之间的 or
关系 - 如果它们中的任何一个对于某个项目是正确的,该项目将被添加到结果中(有时不止一次...)
要实现为 and
,您需要确保在将项目添加到结果之前所有规则都通过该项目。最简单的实现方法是假设结果包含所有元素,然后删除任何不通过规则的元素:
filtered_report = reports.dup
filter_option.each do |f|
filtered_report.reject! do |r|
!r.any? do |k,v|
if f[1] == "="
if f[0].to_sym == k && v == f[2]
true
end
elsif f[1] == ">"
if f[0].to_sym == k && v > f[2].to_i
true
end
elsif f[1] == "<"
if f[0].to_sym == k && v < f[2].to_i
true
end
end
end
end
end
reject!
删除块 return 为真的所有元素,如果任何块 return 为真,则 any?
return 为真。
这不是很像红宝石,但是...对 filtered_option
数组进行一些更改,您可以使它更简洁:
filter_option = [[:accountid, "<", 2],[:first_name, "==", "John"],[:lastname, "==", "deo"]]
reports.select do |h|
filter_option.any? do |field, op, value|
h[field].send(op, value)
end
end
=> [{:accountid=>1, :first_name=>"Elen", :lastname=>"Adam"},
{:accountid=>1, :first_name=>"niokie", :lastname=>"c"},
{:accountid=>2, :first_name=>"john", :lastname=>"deo"}]
reports.select do |h|
filter_option.all? do |field, op, value|
h[field].send(op, value)
end
end
=> []
上面的代码是做什么的?
select
returns 块 returns true
的唯一元素。
any?
returns true
如果块的任何运行(每个元素一次)returns true
。
all?
returns 'true' if all 运行块 return true
.
send(op, value)
实际上 运行 元素上的运算符(即 "niokie" == "John"
),并且 return 是它的值。
试试下面的代码
filtered_report = []
filter_option_length = filter_option.length
reports.each do |report|
condition_satisfied_flag = 0
filter_option.each do |filter|
if filter[1] == "="
condition_satisfied_flag += 1 if report[filter[0].to_sym].to_s.downcase == filter[2].downcase
end
if filter[1] == "<"
condition_satisfied_flag += 1 if report[filter[0].to_sym].to_s.downcase < filter[2].downcase
end
if filter[1] == ">"
condition_satisfied_flag += 1 if report[filter[0].to_sym].to_s.downcase > filter[2].downcase
end
end
filtered_report << report if condition_satisfied_flag == filter_option_length
end
我正在尝试对数据实施动态过滤器。我有过滤选项的多维数组:
filter_option = [["accountid", "<", "2"],["first_name", "=", "John"],["lastname", "=", "deo"]]
和哈希数组为:
reports = [{accountid: 1, first_name: "Elen", lastname: "Adam"},{accountid: 1, first_name: "niokie", lastname: "c"},{accountid: 2, first_name: "john", lastname: "deo"},{accountid: 4, first_name: "sherry", lastname: "b"},{accountid: 3, first_name: "Jimmy", lastname: "S"}]
所有过滤器选项元素应与 report
数组的每个散列相匹配。例如,在 filter_option
中,我们有 account_id < 2
、first_name = john
和 last_name = deo
。所以我需要那个满足所有这些过滤器的散列。
如果filter_option
是:
filter_option = [["accountid", ">", "2"]]
那么输出应该是:
filtered_report = [{accountid: 4, first_name: "sherry", lastname: "b"},{accountid: 3, first_name: "Jimmy", lastname: "S"}]
如果过滤器选项是:
filter_option = [["accountid", "=", "2"],["first_name","=","john"],["lastname","=","deo"]]
那么输出应该是:
filtered_report = [{accountid: 2, first_name: "john", lastname: "deo"}]
如果过滤器选项是:
filter_option = [["accountid", ">", "3"],["first_name","=","sherry"],["lastname","=","b"]]
那么输出应该是:
filtered_report = [{accountid: 4, first_name: "sherry", lastname: "b"}]
我没有得到我需要的解决方案。有谁知道获得我需要的输出的最佳解决方案是什么?
我写的代码如下:
filtered_report = []
filter_option.each do |f|
reports.each do |r|
r.each do |k,v|
if f[1] == "="
if f[0].to_sym == k && v == f[2]
filtered_report << r
end
elsif f[1] == ">"
if f[0].to_sym == k && v > f[2].to_i
filtered_report << r
end
elsif f[1] == "<"
if f[0].to_sym == k && v < f[2].to_i
filtered_report << r
end
end
end
end
end
当我执行这段代码时,我会得到如下输出:
filtered_report = [{:accountid=>1, :first_name=>"Elen", :lastname=>"Adam"}, {:accountid=>1, :first_name=>"Elen", :lastname=>"Adam"}, {:accountid=>2, :first_name=>"john", :lastname=>"deo"}, {:accountid=>2, :first_name=>"john", :lastname=>"deo"}]
这是不正确的,因为数组中没有一个散列满足 filter_option
数组中给定的所有过滤器,输出应该是 nil
.
您的代码实现了过滤器选项之间的 or
关系 - 如果它们中的任何一个对于某个项目是正确的,该项目将被添加到结果中(有时不止一次...)
要实现为 and
,您需要确保在将项目添加到结果之前所有规则都通过该项目。最简单的实现方法是假设结果包含所有元素,然后删除任何不通过规则的元素:
filtered_report = reports.dup
filter_option.each do |f|
filtered_report.reject! do |r|
!r.any? do |k,v|
if f[1] == "="
if f[0].to_sym == k && v == f[2]
true
end
elsif f[1] == ">"
if f[0].to_sym == k && v > f[2].to_i
true
end
elsif f[1] == "<"
if f[0].to_sym == k && v < f[2].to_i
true
end
end
end
end
end
reject!
删除块 return 为真的所有元素,如果任何块 return 为真,则 any?
return 为真。
这不是很像红宝石,但是...对 filtered_option
数组进行一些更改,您可以使它更简洁:
filter_option = [[:accountid, "<", 2],[:first_name, "==", "John"],[:lastname, "==", "deo"]]
reports.select do |h|
filter_option.any? do |field, op, value|
h[field].send(op, value)
end
end
=> [{:accountid=>1, :first_name=>"Elen", :lastname=>"Adam"},
{:accountid=>1, :first_name=>"niokie", :lastname=>"c"},
{:accountid=>2, :first_name=>"john", :lastname=>"deo"}]
reports.select do |h|
filter_option.all? do |field, op, value|
h[field].send(op, value)
end
end
=> []
上面的代码是做什么的?
select
returns 块 returns true
的唯一元素。
any?
returns true
如果块的任何运行(每个元素一次)returns true
。
all?
returns 'true' if all 运行块 return true
.
send(op, value)
实际上 运行 元素上的运算符(即 "niokie" == "John"
),并且 return 是它的值。
试试下面的代码
filtered_report = []
filter_option_length = filter_option.length
reports.each do |report|
condition_satisfied_flag = 0
filter_option.each do |filter|
if filter[1] == "="
condition_satisfied_flag += 1 if report[filter[0].to_sym].to_s.downcase == filter[2].downcase
end
if filter[1] == "<"
condition_satisfied_flag += 1 if report[filter[0].to_sym].to_s.downcase < filter[2].downcase
end
if filter[1] == ">"
condition_satisfied_flag += 1 if report[filter[0].to_sym].to_s.downcase > filter[2].downcase
end
end
filtered_report << report if condition_satisfied_flag == filter_option_length
end