过滤哈希数组以仅保留其哈希包含数组中包含的键的那些元素?

Filter an array of hashes to keep only those elements whose hashes contain a key contained in an array?

这里我们有一个哈希数组。我们如何才能只保留数组中至少包含一个键的哈希值?

# array of hashes
@arr_of_h = [{first: 10},
{second: 10, secondB: 10},
{third: 10, thirdB: 10}]

# array
arr = ["first", "third"]

期望的输出

@output = [{:first=>10}, {:third=>10, :thirdB=>10}]

使用 Array select 尝试以下操作:

select will return an array containing elements which match the condition provided on the block.

希望数组每个索引的散列只包含一个键

 @arr_of_h.select{ |element| arr.include?(element.keys.first.to_s) }

编辑#1

To find the record which at least has one key contained in an array

我们可以通过Array select数组实现吗?

 @arr_of_h.select{ |element| element.keys.any? {|element| arr.include?(element.to_s) }}

如果您的数组中有多个键的散列,并且如果散列键之一出现在 'keep' 数组中,您希望保留散列,这将起作用。

arr_of_h.delete_if { |hash| (arr & (hash.keys.map(&:to_s))).empty? }

正如 Cary 正确指出的那样,这确实会改变数组。如果您不想改变数组:

arr_of_h.select { |hash| (arr & (hash.keys.map(&:to_s))).any? }

如果速度很重要,并且数组有很多元素,这意味着需要多次查找,请使用 set。此外,为了速度,在开始时将数组转换为符号,而不是在 select 循环中将其转换。请注意,对于 OP 描述的特定情况,速度改进即使有也很小,因为所有输入都很小。

require "Set"
@arr_of_h = [{first: 10}, {second: 10}, {third: 10}]
arr = ["first", "third"]
arr_as_set = arr.map(&:to_sym).to_set
@output = @arr_of_h.select { |h| arr_as_set.include?(h.keys.first) }
puts @output
# Prints: 
# {:first=>10}
# {:third=>10}

另请参见:

Set#include? docs

More on Set#include?
Speed comparisons for arrays, sets, and hashes, with benchmarks