Comment puis-je vérifier si mon tableau contient un object?

J’ai un tableau @horses = [] que je remplis avec des chevaux au hasard.

Comment puis-je vérifier si mon tableau @horses contient un cheval déjà inclus (existe)?

J’ai essayé quelque chose comme:

 @suggested_horses = [] @suggested_horses <rand(Horse.count)) while @suggested_horses.length rand(Horse.count)) unless @suggested_horses.exists?(horse.id) @suggested_horses<< horse end end 

J’ai aussi essayé avec include? mais j’ai vu que c’était pour des cordes seulement. Avec exists? Je reçois l’erreur suivante:

 undefined method `exists?' for # 

Donc, la question est de savoir comment vérifier si mon tableau contient déjà un “cheval” pour ne pas le remplir avec le même cheval?

Les tableaux dans Ruby n’existent pas exists? méthode, mais ils ont un include? méthode décrite dans les documents . Quelque chose comme

 unless @suggested_horses.include?(horse) @suggested_horses < < horse end 

devrait travailler hors de la boîte.

Si vous voulez vérifier si un object est dans le tableau en vérifiant un atsortingbut sur l’object, vous pouvez en utiliser any? et passer un bloc évalué à true ou false:

 unless @suggested_horses.any? {|h| h.id == horse.id } @suggested_horses < < horse end 

Pourquoi ne pas le faire simplement en choisissant huit numéros différents de 0 à Horse.count et l’utiliser pour obtenir vos chevaux?

 offsets = (0...Horse.count).to_a.sample(8) @suggested_horses = offsets.map{|i| Horse.first(:offset => i) } 

Cela présente l’avantage supplémentaire de ne pas créer une boucle infinie si votre firebase database contient moins de 8 chevaux.

Note: Array#sample est nouveau à 1.9 (et entrant dans 1.8.8), donc mettez à niveau votre Ruby, require 'backports' ou utilisez quelque chose comme shuffle.first(n) .

#include? devrait fonctionner, cela fonctionne pour des objects généraux , pas seulement des chaînes. Votre problème dans l’exemple de code est ce test:

 unless @suggested_horses.exists?(horse.id) @suggested_horses< < horse end 

(même en supposant l'utilisation de #include? ). Vous essayez de rechercher un object spécifique, pas pour id. Donc ça devrait être comme ça:

 unless @suggested_horses.include?(horse) @suggested_horses < < horse end 

ActiveRecord a redéfini l' opérateur de comparaison pour les objects afin de ne rechercher que son état (nouveau / créé) et son identifiant

Array’s include? méthode accepte n’importe quel object, pas seulement une chaîne. Cela devrait fonctionner:

 @suggested_horses = [] @suggested_horses < < Horse.first(:offset => rand(Horse.count)) while @suggested_horses.length < 8 horse = Horse.first(:offset => rand(Horse.count)) @suggested_horses < < horse unless @suggested_horses.include?(horse) end 
  • Array#include? Documentation

Donc, la question est de savoir comment vérifier si mon tableau contient déjà un “cheval” pour ne pas le remplir avec le même cheval?

Bien que les réponses concernent la recherche dans le tableau pour voir si une chaîne ou un object particulier existe, cela ne va pas du tout, car la recherche prendra plus de temps à mesure que le tableau s’agrandit.

Utilisez plutôt un hachage ou un ensemble . Les deux ne permettent qu’une seule instance d’un élément particulier. Set se comportera plus près d’un tableau mais n’autorisera qu’une seule instance. Il s’agit d’une approche plus préventive qui évite la duplication en raison de la nature du conteneur.

 hash = {} hash['a'] = nil hash['b'] = nil hash # => {"a"=>nil, "b"=>nil} hash['a'] = nil hash # => {"a"=>nil, "b"=>nil} require 'set' ary = [].to_set ary < < 'a' ary << 'b' ary # => # ary < < 'a' ary # => # 

Hash utilise des paires nom / valeur, ce qui signifie que les valeurs ne seront d’aucune utilité réelle, mais il semble y avoir un peu de vitesse supplémentaire avec un Hash, basé sur certains tests.

 require 'benchmark' require 'set' ALPHABET = ('a' .. 'z').to_a N = 100_000 Benchmark.bm(5) do |x| x.report('Hash') { N.times { h = {} ALPHABET.each { |i| h[i] = nil } } } x.report('Array') { N.times { a = Set.new ALPHABET.each { |i| a < < i } } } end 

Quelles sorties:

  user system total real Hash 8.140000 0.130000 8.270000 ( 8.279462) Array 10.680000 0.120000 10.800000 ( 10.813385) 

Ce …

 horse = Horse.find(:first,:offset=>rand(Horse.count)) unless @suggested_horses.exists?(horse.id) @suggested_horses< < horse end 

Devrait probablement être ce ...

 horse = Horse.find(:first,:offset=>rand(Horse.count)) unless @suggested_horses.include?(horse) @suggested_horses< < horse end