[2, 6, 13, 99, 27].include?(2)
适用于检查数组是否包含一个值。但是,如果我想检查数组是否包含多个值列表中的任何一个,该怎么办?有没有比做Array.include?(a) or Array.include?(b) or Array.include?(c) ...
更简短的方法?
答案 0 :(得分:79)
你可以取两个数组的交集,看看它是不是空的:
([2, 6, 13, 99, 27] & [2, 6]).any?
答案 1 :(得分:20)
您可以将Enumerable#any?方法与代码块一起使用来测试是否包含多个值。例如,要检查6或13:
[2, 6, 13, 99, 27].any? { |i| [6, 13].include? i }
答案 2 :(得分:15)
我有兴趣了解这些不同方法在性能方面的比较,而不是对手头的问题进行比较,而是对阵列与集合交集,数组与集合include?
和include?
的一般比较更多对于数组,vs index
。我将编辑以添加建议的其他方法,如果您想查看不同的基准参数,请告诉我。
我希望看到更多的SO答案的基准测试。这并不困难或耗时,它可以提供有用的见解。我发现大部分时间都在准备测试用例。请注意,我已将要测试的方法放在模块中,因此如果要对其他方法进行基准测试,我只需要将该方法添加到模块中。
方法比较
module Methods
require 'set'
def august(a,b) (a&b).any? end
def gnome_inc(a,b) a.any? { |i| b.include? i } end
def gnome_ndx(a,b) a.any? { |i| b.index i } end
def gnome_set(a,b) bs=b.to_set; a.any? { |i| bs.include? i } end
def vii_stud(a,b) as, bs = Set.new(a), Set.new(b); as.intersect?(bs) end
end
include Methods
@methods = Methods.instance_methods(false)
#=> [:august, :gnome_inc, :gnome_ndx, :gnome_set, :vii_stud]
测试数据
def test_data(n,m,c,r)
# n: nbr of elements in a
# m: nbr of elements in b
# c: nbr of elements common to a & b
# r: repetitions
r.times.each_with_object([]) { |_,a|
a << [n.times.to_a.shuffle, [*(n-c..n-c-1+m)].shuffle] }
end
d = test_data(10,4,2,2)
#=> [[[7, 8, 0, 3, 2, 9, 1, 6, 5, 4], [11, 10, 9, 8]],
# [[2, 6, 3, 4, 7, 8, 0, 9, 1, 5], [ 9, 11, 10, 8]]]
# Before `shuffle`, each of the two elements is:
#=> [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [8, 9, 10, 11]]
def compute(d, m)
d.each_with_object([]) { |(a,b),arr| arr << send(m, a, b) }
end
compute(d, :august)
#=> [true, true]
确认方法返回相同的值
d = test_data(1000,100,10,3)
r0 = compute(d, @methods.first)
puts @methods[1..-1].all? { |m| r0 == compute(d, m) }
#=> true
基准代码
require 'benchmark'
@indent = methods.map { |m| m.to_s.size }.max
def test(n, m, c, r, msg)
puts "\n#{msg}"
puts "n = #{n}, m = #{m}, overlap = #{c}, reps = #{r}"
d = test_data(n, m, c, r)
Benchmark.bm(@indent) do |bm|
@methods.each do |m|
bm.report m.to_s do
compute(d, m)
end
end
end
end
<强>测试强>
n = 100_000
m = 1000
test(n, m, 0, 1, "Zero overlap")
test(n, m, 1000, 1, "Complete overlap")
test(n, m, 1, 20, "Overlap of 1")
test(n, m, 5, 20, "Overlap of 5")
test(n, m, 10, 20, "Overlap of 10")
test(n, m, 20, 20, "Overlap of 20")
test(n, m, 50, 20, "Overlap of 50")
test(n, m, 100, 20, "Overlap of 100")
Zero overlap
n = 100000, m = 1000, overlap = 0, reps = 1
user system total real
august 0.010000 0.000000 0.010000 ( 0.005491)
gnome_inc 4.480000 0.010000 4.490000 ( 4.500531)
gnome_ndx 0.810000 0.000000 0.810000 ( 0.822412)
gnome_set 0.030000 0.000000 0.030000 ( 0.031668)
vii_stud 0.080000 0.010000 0.090000 ( 0.084283)
Complete overlap
n = 100000, m = 1000, overlap = 1000, reps = 1
user system total real
august 0.000000 0.000000 0.000000 ( 0.005841)
gnome_inc 0.010000 0.000000 0.010000 ( 0.002521)
gnome_ndx 0.000000 0.000000 0.000000 ( 0.000350)
gnome_set 0.000000 0.000000 0.000000 ( 0.000655)
vii_stud 0.090000 0.000000 0.090000 ( 0.097850)
Overlap of 1
n = 100000, m = 1000, overlap = 1, reps = 20
user system total real
august 0.110000 0.000000 0.110000 ( 0.116276)
gnome_inc 61.790000 0.100000 61.890000 ( 62.058320)
gnome_ndx 10.100000 0.020000 10.120000 ( 10.144649)
gnome_set 0.360000 0.000000 0.360000 ( 0.357878)
vii_stud 1.450000 0.050000 1.500000 ( 1.501705)
Overlap of 5
n = 100000, m = 1000, overlap = 5, reps = 20
user system total real
august 0.110000 0.000000 0.110000 ( 0.113747)
gnome_inc 16.550000 0.050000 16.600000 ( 16.728505)
gnome_ndx 2.470000 0.000000 2.470000 ( 2.475111)
gnome_set 0.100000 0.000000 0.100000 ( 0.099874)
vii_stud 1.630000 0.060000 1.690000 ( 1.703650)
Overlap of 10
n = 100000, m = 1000, overlap = 10, reps = 20
user system total real
august 0.110000 0.000000 0.110000 ( 0.112674)
gnome_inc 10.090000 0.020000 10.110000 ( 10.131339)
gnome_ndx 1.470000 0.000000 1.470000 ( 1.478400)
gnome_set 0.060000 0.000000 0.060000 ( 0.062762)
vii_stud 1.430000 0.050000 1.480000 ( 1.476961)
Overlap of 20
n = 100000, m = 1000, overlap = 20, reps = 20
user system total real
august 0.100000 0.000000 0.100000 ( 0.108350)
gnome_inc 4.020000 0.000000 4.020000 ( 4.026290)
gnome_ndx 0.660000 0.010000 0.670000 ( 0.663001)
gnome_set 0.030000 0.000000 0.030000 ( 0.024606)
vii_stud 1.380000 0.050000 1.430000 ( 1.437340)
Overlap of 50
n = 100000, m = 1000, overlap = 50, reps = 20
user system total real
august 0.120000 0.000000 0.120000 ( 0.121278)
gnome_inc 2.170000 0.000000 2.170000 ( 2.236737)
gnome_ndx 0.310000 0.000000 0.310000 ( 0.308336)
gnome_set 0.020000 0.000000 0.020000 ( 0.015326)
vii_stud 1.220000 0.040000 1.260000 ( 1.259828)
Overlap of 100
n = 100000, m = 1000, overlap = 100, reps = 20
user system total real
august 0.110000 0.000000 0.110000 ( 0.112739)
gnome_inc 0.720000 0.000000 0.720000 ( 0.712265)
gnome_ndx 0.100000 0.000000 0.100000 ( 0.105420)
gnome_set 0.010000 0.000000 0.010000 ( 0.009398)
vii_stud 1.400000 0.050000 1.450000 ( 1.447110)
答案 3 :(得分:3)
简单方法:
([2, 6] - [2, 6, 13, 99, 27]).empty?
答案 4 :(得分:0)
require 'set'
master = Set.new [2, 6, 13, 99, 27]
data = Set.new [27, -3, -4]
#puts data.subset?(master) ? 'yes' : 'no' #per @meager comment
puts data.intersect?(master) ? 'yes' : 'no'
--output:--
yes
答案 5 :(得分:0)
这有效 - 如果任何值匹配:
arr = [2, 6, 13, 99, 27]
if (arr - [2, 6]).size < arr.size
puts 'element match found'
else
puts 'element not found'
end
答案 6 :(得分:0)
我最喜欢在规范中执行此操作的方法之一是将数组和值转换为Set并通过#superset?&amp; #subset?方法。
例如:
[1, 2, 3, 4, 5].to_set.superset?([1, 2, 3].to_set) # true
[1, 2, 3].to_set.subset?([1, 2, 3, 4, 5].to_set) # true
[1, 2].to_set.subset?([1, 2].to_set) # true
[1, 2].to_set.superset?([1, 2].to_set) # true
但是,作为一个集合意味着集合中的所有值都是唯一的,因此它可能并不总是合适的:
[1, 1, 1, 1, 1].to_set.subset? [1, 2].to_set # true
为了避免每次我为此定义匹配器时调用.to_set
:
it 'returns array of "shown" proposals' do
expect(body_parsed.first.keys).to be_subset_of(hidden_prop_attrs)
end
在我看来,作为一个超集或一个子集比阅读更具可读性:
([1, 2, 3] & [1, 2]).any?
但是,将数组转换为集合可能效率较低。权衡¯\ _(ツ)_ /¯
答案 7 :(得分:0)
我用以下这些扩展Array:
class Array
def include_exactly?(values)
self.include_all?(values) && (self.length == values.length)
end
def include_any?(values)
values.any? {|value| self.include?(value)}
end
def include_all?(values)
values.all? {|value| self.include?(value)}
end
def exclude_all?(values)
values.all? {|value| self.exclude?(value)}
end
end