web-dev-qa-db-fra.com

Comment vérifier si les valeurs d'un tableau incluent une ou plusieurs valeurs?

Je cherche à voir si un tableau a une ou plusieurs valeurs à l'intérieur. Par exemple, quelque chose comme ça:

[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

Bien sûr, le "inclure?" méthode ne peut vérifier qu'une valeur. Existe-t-il une méthode pour vérifier plusieurs valeurs?

21
sjsc

EDIT: J'approuve Mark Thomas ' Solution alternative utilisant la version de base Setclass .

Bien que ma solution réponde plus strictement à la question de savoir comment procéder à l'aide de tableaux, sjsc peut tirer avantage de la révision de son propre cas et de l'exploration de l'option consistant à utiliser des ensembles.

Il y a beaucoup de raisons valables pour utiliser des tableaux (maintien de l'ordre, permettant des doublons), pour lesquels les éléments ci-dessous sont encore suffisants, mais si aucun de ceux-ci n'est impliqué, sjsc pourrait en réalité tirer avantage de l'utilisation de Set au lieu de Array, et dans cette mesure, la solution est sémantiquement supérieure.


Je ne connais aucune méthode de bibliothèque qui effectue cela, mais il ne serait pas trop difficile d'écrire votre propre fonction.

class Array
  def subset?(a)
    (self - a).length == 0
  end
end

Je suis sûr qu'il existe des moyens informatiques plus efficaces pour accomplir cela, mais cela devrait faire ce que vous cherchez.

Faire une intersection de tableau fonctionne et revient en gros à la même chose.

class Array
  def subset?(a)
    (self & a).length == length
  end
end

L’optimisation à ce niveau n’aidera pas beaucoup, mais vous ne voudrez pas commencer à comparer les tableaux plusieurs fois:

class Array
  # don't do this
  def subset?(a)
    (self & a) == a
  end
end
16
Steven Xu
>> [1,2,3,4,5,6] & [4,1]
=> [1, 4]
>> [1,2,3,4,5,6] & [7,9]
=> []
>>
57
kurumi

Ceci est une opération définie. Set est dans la bibliothèque standard.

require 'set'

a = Set[1,2,3,4,5,6]
b = Set[4,1]

b.subset? a
#=> true
26
Mark Thomas

Une extension rapide et sale de l'approche de @ Schwartzie:

larger_array = [1,2,3,4,5,6]
smaller_array = [4,1]
smaller_array.all? {|smaller_array_item| larger_array.include?(smaller_array_item)}
6
Andrew Grimm

Sur la base de la suggestion de kurumi et de spyle, voici mon test:

([1,2,3,4,5,6] & [4,1]). # => true

Cependant. transformera tous les objets en vrais

([1,2,3,4,5,6] & [6,7]). # => true

Donc, je pense que cela pourrait être un travail:

([1,2,3,4,5,6] & [6,7]). Length == [6,7] .length # => false

(larger_array & smaller_array) .length == smaller_array.length

4
xjlin0

Quel est le problème avec [1,2,3,4,5,6].include?(4) and [1,2,3,4,5,6].include?(1)?

3
Schwartzie

J'aime la réponse de Kurumi, mais juste pour en lancer une de plus:

>> 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
2
CoderDave

Ma conclusion est que la méthode soustraction est généralement agréable, mais que les objets réels Set sont extrêmement rapides car ils sont clairement optimisés pour ce type de calcul.

Utilisation de ce script: https://Gist.github.com/1996001

J'ai eu ces résultats de référence (sur 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)

Ce que je considère assez surprenant, surtout si vous consultez la 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

2

@kurumi a raison, mais je pensais ajouter que j'utilise parfois cette petite extension quand je ne veux qu'un sous-ensemble d'un tableau (généralement les clés de hachage):

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
1
scragz

Simple et meilleur moyen:

([4,1] - [1,2,3,4,5,6]). Vide? # => true

([4,1] - [4,1,6,2]). Vide? # => true

([4,1] - [3,4,7]). Vide? # => faux

0
user3078630

Pour vérifier les valeurs de tableau contenant un ou plusieurs éléments, vous pouvez convertir un tableau sur "set", puis utiliser "subset?" méthode comme ci-dessous.

    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
Rabendra Sharma

Ceci vérifiera si un élément existe dans un tableau:

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
0
max paspa