开发者

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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜