如何比较多维数组元素与哈希数组

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 < 2first_name = johnlast_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