Ich habe eine Reihe @horses = []
, die ich mit einigen zufälligen Pferden fülle.
Wie kann ich überprüfen, ob mein @horses
Array ein Pferd enthält, das bereits enthalten ist (existiert)?
Ich habe so etwas versucht wie:
@suggested_horses = []
@suggested_horses << Horse.find(:first,:offset=>rand(Horse.count))
while @suggested_horses.length < 8
horse = Horse.find(:first,:offset=>rand(Horse.count))
unless @suggested_horses.exists?(horse.id)
@suggested_horses<< horse
end
end
Ich habe es auch mit versucht, include?
aber ich habe gesehen, dass es nur für Streicher war. Mit exists?
bekomme ich folgenden Fehler:
undefined method `exists?' for #<Array:0xc11c0b8>
Die Frage ist also, wie ich überprüfen kann, ob in meinem Array bereits ein "Pferd" enthalten ist, damit ich es nicht mit demselben Pferd fülle.
ruby-on-rails
ruby
necker
quelle
quelle
Antworten:
Arrays in Ruby haben keine
exists?
Methode, aber sie haben eineinclude?
Methode, wie in den Dokumenten beschrieben . Etwas wieunless @suggested_horses.include?(horse) @suggested_horses << horse end
sollte sofort funktionieren.
quelle
Hash
oderSet
vonstd-lib
.Wenn Sie überprüfen möchten, ob sich ein Objekt im Array befindet, indem Sie ein Attribut für das Objekt überprüfen, können Sie
any?
einen Block verwenden und übergeben, der als wahr oder falsch ausgewertet wird:unless @suggested_horses.any? {|h| h.id == horse.id } @suggested_horses << horse end
quelle
Warum nicht einfach acht verschiedene Zahlen von
0
bis auswählenHorse.count
und damit Ihre Pferde holen?offsets = (0...Horse.count).to_a.sample(8) @suggested_horses = offsets.map{|i| Horse.first(:offset => i) }
Dies hat den zusätzlichen Vorteil, dass es keine Endlosschleife verursacht, wenn Sie weniger als 8 Pferde in Ihrer Datenbank haben.
Hinweis:
Array#sample
ist neu in Version 1.9 (und kommt in Version 1.8.8). Aktualisieren Sie also entweder Ihren Rubyrequire 'backports'
oder verwenden Sie etwas Ähnlichesshuffle.first(n)
.quelle
#include?
sollte funktionieren, funktioniert es für allgemeine Objekte , nicht nur für Zeichenfolgen. Ihr Problem im Beispielcode ist dieser Test:unless @suggested_horses.exists?(horse.id) @suggested_horses<< horse end
(sogar unter Verwendung
#include?
). Sie versuchen, nach einem bestimmten Objekt zu suchen, nicht nach einer ID. So sollte es sein:unless @suggested_horses.include?(horse) @suggested_horses << horse end
ActiveRecord hat den Vergleichsoperator für Objekte neu definiert , damit nur der Status (neu / erstellt) und die ID überprüft werden
quelle
Die
include?
Methode des Arrays akzeptiert jedes Objekt, nicht nur eine Zeichenfolge. Das sollte funktionieren:@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?
Dokumentationquelle
Während es bei den Antworten darum geht, das Array zu durchsuchen, um festzustellen, ob eine bestimmte Zeichenfolge oder ein bestimmtes Objekt vorhanden ist, läuft das wirklich falsch, da die Suche mit zunehmender Größe des Arrays länger dauert.
Verwenden Sie stattdessen entweder einen Hash oder einen Set . Beide erlauben nur eine einzelne Instanz eines bestimmten Elements. Set verhält sich näher an einem Array, lässt jedoch nur eine einzelne Instanz zu. Dies ist ein präventiverer Ansatz, bei dem Doppelarbeit aufgrund der Art des Containers vermieden wird.
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 # => #<Set: {"a", "b"}> ary << 'a' ary # => #<Set: {"a", "b"}>
Hash verwendet Name / Wert-Paare, was bedeutet, dass die Werte keinen wirklichen Nutzen haben, aber es scheint ein bisschen mehr Geschwindigkeit zu geben, wenn ein Hash verwendet wird, basierend auf einigen 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
Welche Ausgänge:
user system total real Hash 8.140000 0.130000 8.270000 ( 8.279462) Array 10.680000 0.120000 10.800000 ( 10.813385)
quelle
Dies ...
horse = Horse.find(:first,:offset=>rand(Horse.count)) unless @suggested_horses.exists?(horse.id) @suggested_horses<< horse end
Sollte wohl das sein ...
horse = Horse.find(:first,:offset=>rand(Horse.count)) unless @suggested_horses.include?(horse) @suggested_horses<< horse end
quelle