my_array.reject { |elem| elem =~ /regex/ }.each { ... }
我感觉这有点笨重,但是我没有找到任何内置的函数可以让我将其更改为my_array.grepv /regex/ { ... }
是否有这样的函数?
Ruby 2.3 实现了一个 Enumerable#grep_v
方法,这正是你需要的。
https://ruby-doc.org/core-2.3.0/Enumerable.html#method-i-grep_v
Symbol#to_proc
怎样帮助链式操作吗?正则表达式也可以实现相同的功能:class Regexp
def to_proc
Proc.new {|string| string =~ self}
end
end
["Ruby", "perl", "Perl", "PERL"].reject(&/perl/i)
=> ["Ruby"]
但你可能不应该这样做。Grep 不仅可以使用正则表达式 - 你可以像下面这样使用它
[1,2, "three", 4].grep(Fixnum)
如果你想要用grep -v来处理它,你需要实现Class#to_proc
,这听起来不太对。
这个怎么样?
arr = ["abc", "def", "aaa", "def"] arr - arr.grep(/a/) #=> ["def", "def"]
我故意包含了一个dup,以确保所有的值都被返回。
那么反转正则表达式呢?
["ab", "ac", "bd"].grep(/^[^a]/) # => ["bd"]
我不相信有内置的东西可以做到这一点,但是很容易添加:
class Array
def grepv(regex, &block)
self.reject { |elem| elem =~ regex }.each(&block)
end
end
myarray.grepv(/regex/) { ... }
你可以做:
my_array.reject{|e| e[/regex/]}.each { ... }
但实际上更简洁和自我记录是很困难的。它可以使用grep(/.../)
编写一些负向先行模式,但我认为这样会更难理解整体操作,因为模式本身更难理解。
尝试使用{{link1:Array#collect!
}}
my_array.collect! do |elem|
if elem =~ /regex/
# do stuff
elem
end
end
编辑:抱歉,此时您需要在之后调用Array#compact
。至少这样可以消除第二个块。但是它会产生更多物理代码。这取决于你做了多少“东西”。
你只需要对正则表达式匹配的结果取反即可。
Enumerable.module_eval do
def grepv regexp
if block_given?
self.each do |item|
yield item if item !~ regexp
end
else
self.find_all do |item|
item !~ regexp
end
end
end
end
非常感谢大家的评论。最终,我是这样做的:
module Enumerable
def grepv(condition)
non_matches = []
self.each do |item|
unless condition === item or condition === item.to_s
non_matches.push(item)
yield item if block_given?
end
end
return non_matches
end
end
因为我刚开始学习 Ruby,所以不确定这是否是最好的方法。与其他人的解决方案相比,它有一点长,但我喜欢它,因为它类似于 Enumerable 的 grep 选项——它可以处理任何能够处理 === 的东西,就像 grep 一样,如果给出一个块,则返回找到的项目,并且无论如何都返回那些不匹配的项目的数组。
我添加了 or to_s
部分,以便可以使用相同的正则表达式匹配数组中插入的任何整数,尽管我可以想象有时这可能会使事情变得很麻烦。
这里再试一次,加入bltxd和Hsiu的答案,并尽可能保留原始grep
的精神(即使有点啰嗦):
module Enumerable
def grepv(condition)
if block_given?
each do |item|
yield item if not condition === item
end
else
inject([]) do |memo, item|
memo << item if not condition === item
memo
end
end
end
end
>> (%w(1 2 3) + [4]).cycle(3).grepv(Fixnum)
=> ["1", "2", "3", "1", "2", "3", "1", "2", "3"]
>> (%w(1 2 3) + [4]).cycle(3).grepv(/[12]/)
=> ["3", 4, "3", 4, "3", 4]
O(n^2)
的项目比较费用。
grep_v
是自Ruby 2.3以来可枚举方法。 - steenslag