【发布时间】:2017-05-23 23:48:25
【问题描述】:
我使用的是 Ruby 2.4。如何检查数组中至少 80% 的元素是否与某个模式匹配?我想看看每个元素是否与正则表达式匹配
/\d\d?\s*-\s*\d\d?/
【问题讨论】:
-
数数并做数学?
-
过滤并比较新数组和旧数组的百分比?
标签: arrays ruby regex matching ruby-2.4
我使用的是 Ruby 2.4。如何检查数组中至少 80% 的元素是否与某个模式匹配?我想看看每个元素是否与正则表达式匹配
/\d\d?\s*-\s*\d\d?/
【问题讨论】:
标签: arrays ruby regex matching ruby-2.4
如果性能确实很重要,您无需检查所有元素以了解是否至少 80% 的元素都符合条件
使用 ruby 2.3,这个实现比 count 解决方案快一点,比 grep 解决方案快两倍:
def pareto_match(array, proportion: 0.8)
min_success= (array.count * proportion).round(4)
max_failures= (array.count * (1 - proportion)).round(4)
success= 0
failure= 0
array.each do |element|
if yield(element)
success+= 1
return true if success >= min_success
else
failure+= 1
return false if failure > max_failures
end
end
end
pareto_match(array){|e| e =~ /\d\d?\s*-\s*\d\d?/}
【讨论】:
min_success 将是 8.0,而 max_failures 将是 1.9999999999999996。
to_i 而不是round(x) 这种情况不起作用:pareto_match(%w(1 2 3 a)){|e| e =~ /\d/}
round(x) 没有多大意义,因为数组不能包含小数元素。我会使用min_success = (array_count * proportion).round 和max_failures = array.count - min_success。您也可以使用ceil 或floor 代替round。
我会写:
(array.count{|item| item =~ /\d\d?\s*-\s*\d\d?/} / array.size) >= 0.8
【讨论】:
您可以将Enumerable#grep 与简单数学结合使用:
array.grep(/\d\d?\s*-\s*\d\d?/).size / array.size.to_f >= 0.8
要进一步缩短,您可以使用Numeric#quo 或Numeric#fdiv:
array.grep(/\d\d?\s*-\s*\d\d?/).size.quo(array.size) >= 0.8
【讨论】:
>= .8?
array.grep(...).size >= 0.8 * array.size,你可以保护to_f
.size.fdiv(array.size) >= 0.8 甚至可能是.size.quo(array.size) >= 80/100r
quo - 直到(谢谢!)!顺便说一句,为什么不用8/10r 而不是80/100r(我想80/100r 的意图更清楚)? :)