将连续过滤器应用于 Ruby 中的数组

Apply successive filters to an array in Ruby

我有一些对象的数组,可能是字符串或数字。我想对这个数组应用一些任意过滤器,并且我希望能够指定过滤器的顺序。这是一个示例(我知道在这个玩具示例中,顺序无关紧要,但我希望能够为另一种情况指定):

filters = [:filter_odd, :filter_multiple_five]
all = (1..10).to_a #[1, 2, ... 10]

filter(all, filters)
# should return [5]

# where, i.e.:
private

def filter_odd(numbers)
  numbers.select(&:odd?)
end

def filter_multiple_five(numbers)
  numbers.select { |number| number%5 == 0 }
end

现在,我知道我可以做到这一点:

odds = filter_odd(all)
filter_multiple_five(odds)

但随着我的要求发生变化,我不得不不断添加更多过滤器,这样做并不是很令人满意。我正在 Ruby.

中寻找一种简洁、实用的方法来执行此操作

好的,剧透,我找到了一个解决方案。因为我在任何地方都找不到这个确切的问题,所以我决定在这里post它:

def filter(array_of_numbers, filters)
  filters.inject(array_of_numbers) do |remaining_numbers, filter|
    send(filter, remaining_numbers)
  end
end

所以,如果你有一些过滤方法:

private

def filter_odd(numbers)
  numbers.select(&:odd?)
end

def filter_multiple_five(numbers)
  numbers.select { |number| number%5 == 0 }
end

以及过滤方法名称列表(作为符号)和一些数据:

filters = [:filter_odd, :filter_multiple_five]
all = (1..10).to_a #[1, 2, ... 10]

调用filtersreturns正确的结果。在第一个过滤器之后,它只产生块的几率,在第二个过滤器之后它产生 returns 5 的奇数倍数:

filter(all, filters)
=> [5]

您可以使用blocks,这是一种灵活的方式。如果你对块不熟悉,这个可以作为参考:understanding-ruby-blocks-procs-and-lambdas

class Array
   def filter
       self.select{ |e| yield(e)} if block_given?
   end
end

arr = (1..10).to_a
puts arr.filter{ |n|  n % 5 == 0 }.inspect
puts arr.filter{ |n|  n.odd? }.inspect
puts arr.filter{ |n|  n % 3 == 0 }.inspect

输出:

[5, 10]
[1, 3, 5, 7, 9]
[3, 6, 9]