How do you check if an array's values includes one or multiple values?
I'm looking to see if an array has one or more values inside i开发者_StackOverflow中文版t. For instance, something like so:
[1,2,3,4,5,6].include?([4,1]) # => true
[4,1,6,2].include?([4,1]) # => true
[3,4,7].include?([4,1]) # => false
Of course, the "include?" method can only check one value. Is there a method to check for multiple values?
>> [1,2,3,4,5,6] & [4,1]
=> [1, 4]
>> [1,2,3,4,5,6] & [7,9]
=> []
>>
This is a set operation. Set
is in the standard library.
require 'set'
a = Set[1,2,3,4,5,6]
b = Set[4,1]
b.subset? a
#=> true
EDIT: I endorse Mark Thomas' alternate solution that uses the core Set
class.
While my solution more strictly answers the question at hand of how to do this with arrays, sjsc may benefit from reviewing his own case and exploring the option of using sets instead.
There are plenty of valid reasond to use arrays (maintaining order, allowing for duplicates), for which the below still suffices, but if none of these are involved, sjsc might actually benefit from using Set instead of Array, and to that extent, Mark's solution is semantically superior.
I don't know of any library method that does this, but it wouldn't be too hard to write your own function.
class Array
def subset?(a)
(self - a).length == 0
end
end
I'm sure there are computationally more efficient ways to accomplish this, but this should do what you're looking for.
Doing array intersection works and basically amounts to the same thing.
class Array
def subset?(a)
(self & a).length == length
end
end
Optimization at this level isn't going to help matters too much, but what you don't want to do is start comparing arrays multiple times:
class Array
# don't do this
def subset?(a)
(self & a) == a
end
end
A quick and dirty extension to @Schwartzie's approach:
larger_array = [1,2,3,4,5,6]
smaller_array = [4,1]
smaller_array.all? {|smaller_array_item| larger_array.include?(smaller_array_item)}
Base on kurumi and spyle's suggestion, here are my test:
([1,2,3,4,5,6] & [4,1]).any? #=> true
However, .any? will turn any objects to true
([1,2,3,4,5,6] & [6,7]).any? #=> true
So I think here might be a working one:
([1,2,3,4,5,6] & [6,7]).length == [6,7].length #=> false
( bigger_array & smaller_array ).length == smaller_array.length
What's wrong with [1,2,3,4,5,6].include?(4) and [1,2,3,4,5,6].include?(1)
?
I like kurumi's answer, but just to throw one more out there:
>> set1 = [1,2,3,4,5,6]
[
[0] 1,
[1] 2,
[2] 3,
[3] 4,
[4] 5,
[5] 6
]
>> set2 = [4,1]
[
[0] 4,
[1] 1
]
>> set1.any?{ |num| set2.include?(num) }
true
>> set2 = [8,9]
[
[0] 8,
[1] 9
]
>> set1.any?{ |num| set2.include?(num) }
false
My conclusion is that the Subtraction method is generally nice, but actual Set objects are blazing fast since they are clearly optimized for this type of computation.
Using this script: https://gist.github.com/1996001
I got these benchmark results (on Ruby 1.9.2p290):
SUBTRACTION
- subset
0.180000 0.000000 0.180000 ( 0.189767)
- partial subset
0.170000 0.000000 0.170000 ( 0.178700)
- non subset
0.180000 0.000000 0.180000 ( 0.177606)
INTERSECTION
- subset
0.190000 0.000000 0.190000 ( 0.194149)
- partial subset
0.190000 0.000000 0.190000 ( 0.191253)
- non subset
0.190000 0.000000 0.190000 ( 0.195798)
SET
- subset
0.050000 0.000000 0.050000 ( 0.048634)
- partial subset
0.040000 0.000000 0.040000 ( 0.045927)
- non subset
0.050000 0.010000 0.060000 ( 0.052925)
Which I consider pretty startling, especially if you check out the source:
# File 'lib/set.rb', line 204
def subset?(set)
set.is_a?(Set) or raise ArgumentError, "value must be a set"
return false if set.size < size
all? { |o| set.include?(o) }
end
via: http://rubydoc.info/stdlib/set/1.9.2/Set#subset%3F-instance_method
@kurumi has it right but I thought I'd add that I sometimes use this little extension when I only want a subset of an array (usually the hash keys though):
class Hash
# Usage { :a => 1, :b => 2, :c => 3}.except(:a) -> { :b => 2, :c => 3}
def except(*keys)
self.reject { |k,v|
keys.include? k
}
end
# Usage { :a => 1, :b => 2, :c => 3}.only(:a) -> {:a => 1}
def only(*keys)
self.dup.reject { |k,v|
!keys.include? k
}
end
end
class Array
def except(*values)
self.reject { |v|
values.include? v
}
end
def only(*values)
self.reject { |v|
!values.include? v
}
end
end
Simple and best way :
([4,1] - [1,2,3,4,5,6]).empty? # => true
([4,1] - [4,1,6,2]).empty? # => true
([4,1] - [3,4,7]).empty? # => false
This will check whether an element exists in a array:
students = ["jim", "bob", "sally"]
teachers = ["mrs. jones", "mrs. sharpe", "mrs. ray"]
puts "what's your name ?"
answer = gets.chomp
if answer.include?(students.to_s)
puts "you are a student"
elsif
puts "you are a teacher"
end
For checking array values contain single or multiple element you can convert array on "set" then can use "subset?" method like below.
require "set"
a = [1,2,3,4,5,6]
b = [3,6]
b.to_set.subset?a.to_set //true
b= [3,7]
b.to_set.subset?a.to_set //false
精彩评论