Ruby - Test für Array

265

Was ist der richtige Weg zu:

is_array("something") # => false         (or 1)

is_array(["something", "else"]) # => true  (or > 1)

oder um die Anzahl der darin enthaltenen Elemente zu ermitteln?

BuddyJoe
quelle
7
Möchten Sie ein tatsächliches Array oder nur etwas Array-ähnliches?
Kathy Van Stone
1
In Ruby gibt es keine Typensicherheit. Machen Sie sich keine Sorgen, dass Ihre Variable ein Array ist oder nicht. Die Methode sollte davon ausgehen, dass dies der Fall ist, und die Anzahl der Aufrufe
aufrufen
Bitte lesen Sie die Antworten von zgchurch und DigitalRoss, um mehr über Ruby zu erfahren.
DanT

Antworten:

516

Sie möchten wahrscheinlich verwenden kind_of().

>> s = "something"
=> "something"
>> s.kind_of?(Array)
=> false
>> s = ["something", "else"]
=> ["something", "else"]
>> s.kind_of?(Array)
=> true
ry.
quelle
31
Es gibt auch is_a?und instance_of?. Siehe stackoverflow.com/questions/3893278/…
Nathan Long
2
Die Typprüfung ist für Java. Rufen Sie einfach count für die Variable auf. Schreiben Sie Komponententests, um sicherzustellen, dass die Methode wie erwartet funktioniert.
user132447
14
@ user132447 tatsächlich ist Java typsicher, so dass Sie sich keine Gedanken über das Überprüfen von Typen machen müssen
grinch
8
Ich habe dies jetzt abgelehnt, da ich nicht denke, dass dies eine gute Praxis in einer Sprache wie Ruby ist. Die Antwort von @zgchurch ist eindeutig eine viel idiomatischere Herangehensweise an die Frage. In solchen Fällen halte ich es für viel sinnvoller, herauszufinden, was das OP bedeutet, als ihm blind eine Schrotflinte zu geben ...
Per Lundberg
1
Warum sollten Sie kind_of?()andere Lösungen verwenden? Einige Erklärungen zu den Vorteilen Ihrer Antwort gegenüber anderen wären für zukünftige Leser hilfreich.
AlbertEngelB
148

Sind Sie sicher , dass es muss ein Array sein? Möglicherweise können Sie verwenden, respond_to?(method)damit Ihr Code für ähnliche Dinge funktioniert, die nicht unbedingt Arrays sind (möglicherweise eine andere enumberable Sache). Wenn Sie tatsächlich eine benötigen array, ist der Beitrag, der die Array#kind\_of?Methode beschreibt, am besten.

['hello'].respond_to?('each')
zgchurch
quelle
1
In diesem Fall bin ich sicher, dass es sich um ein Array handelt. Aber schön, diese Methode auch zu kennen. +1
BuddyJoe
Interessante Idee, ich verwende Push / Pop für eine Datenstruktur. Würde etwas anderes als Arrays auf diese Methoden reagieren?
Drew
3
Wenn Sie etwas Array-ähnlicheres möchten, möchten Sie vielleicht respond_to?(:to_ary).
Andrew Grimm
21
Im Allgemeinen ist dies eine gute Vorgehensweise für die OO-Entwicklung. Ich habe gelesen, wo jemand im Grunde gesagt hat: Stellen Sie sich nicht vor, dass Sie Methoden für Ihre Objekte aufrufen. Sie senden ihnen Nachrichten. Wenn ein Objekt weiß, wie es auf Ihre Nachricht reagiert, ist es Ihnen egal, um welche Klasse es sich handelt oder ob es eine Methode mit diesem Namen hat oder ob es dynamisch eine Antwort über method_missing erstellt. Das Wichtigste ist, kann es auf Ihre Nachricht antworten? Dies ermöglicht eine bessere Abstraktion von Funktion und Implementierung. Sie können ändern, welches Objekt Sie später verwenden, solange es noch korrekt reagiert.
Nathan Long
2
Das einzige Problem dabei ist, dass ich überprüfen möchte, ob etwas indiziert iterierbar ist, sodass Arrays, verknüpfte Listen usw. cool wären, aber ich möchte keine Schlüsselwertspeicher wie Hashes?
Colton Voege
58

Anstatt nur zu testen, Array,konvertieren Sie alles, was Sie erhalten, in eine Ebene, Array,sodass Ihr Code nur den einen Fall behandeln muss.

t = [*something]     # or...
t = Array(something) # or...
def f *x
    ...
end

Ruby hat verschiedene Möglichkeiten, eine API zu harmonisieren, die ein Objekt oder ein Array von Objekten aufnehmen kann. Wenn Sie also raten, warum Sie wissen möchten, ob es sich bei einem Array um ein Array handelt, habe ich einen Vorschlag.

Der Splat- Operator enthält viel Magie, die Sie nachschlagen können, oder Sie können einfach aufrufen Array(something), um bei Bedarf einen Array-Wrapper hinzuzufügen. Es ist ähnlich wie [*something]in diesem einen Fall.

def f x
  p Array(x).inspect
  p [*x].inspect
end
f 1         # => "[1]"
f [1]       # => "[1]"
f [1,2]     # => "[1, 2]"

Oder Sie können den Splat in der Parameterdeklaration verwenden und dann .flatteneine andere Art von Kollektor erhalten. (Für diese Angelegenheit könnten Sie auch .flattenoben anrufen .)

def f *x
  p x.flatten.inspect
end         # => nil
f 1         # => "[1]"
f 1,2       # => "[1, 2]"
f [1]       # => "[1]"
f [1,2]     # => "[1, 2]"
f [1,2],3,4 # => "[1, 2, 3, 4]"

Und dank Gregschlom ist es manchmal schneller, es einfach zu benutzen, Array(x)weil es, wenn es bereits ein Arrayist, kein neues Objekt erstellen muss.

DigitalRoss
quelle
Sie sagen also, wenn es sich um ein einzelnes Element handelt, wird es zu einem Array mit einem einzelnen Element?
BuddyJoe
Ja, und wenn es sich bereits um ein Array handelt, wird es beibehalten, ohne dass ein zweiter Array-Wrapper hinzugefügt wird.
DigitalRoss
2
Vergiss nicht : [*nil] => []. Möglicherweise erhalten Sie ein leeres Array.
Christopher Oezbek
3
Die Verwendung Array(foo)ist viel effizienter als[*foo]
Gregschlom
23

[1,2,3].is_a? Array bewertet als wahr.

dipole_moment
quelle
1
Was trägt dies zu den Antworten bei, die seit fast sieben Jahren auf der Website sind?
Martin Tournoij
6
@Carpetsmoker Es gibt keine präzise Antwort, auf die is_a?in diesem gesamten Thread verwiesen wird. Der nächste ist a [1,2,3].is_a? Enumerable. Ich denke immer noch, dass es sich lohnt, diese Antwort zu haben.
dipole_moment
4
Weißt du ... du hast tatsächlich Recht ... Ich hätte schwören können, dass ich das dort oben früher gesehen habe: - / Habe eine positive Bewertung!
Martin Tournoij
16

Es hört sich so an, als ob Sie nach etwas suchen, das ein Konzept von Gegenständen hat. Ich würde daher empfehlen zu sehen, ob es ist Enumerable. Das garantiert auch die Existenz von #count.

Zum Beispiel,

[1,2,3].is_a? Enumerable
[1,2,3].count

beachten Sie, dass, während size, lengthund countalle arbeiten für Arrays, counthier die richtige Bedeutung ist - (zum Beispiel 'abc'.lengthund 'abc'.sizebeide arbeiten, aber 'abc'.countnicht funktioniert ähnlich).

Achtung: Ein String ist_a? Aufzählbar, vielleicht ist dies nicht das, was Sie wollen ... hängt von Ihrem Konzept eines Array-ähnlichen Objekts ab.

Peter
quelle
11

Versuchen:

def is_array(a)
    a.class == Array
end

EDIT : Die andere Antwort ist viel besser als meine.

Lucas Jones
quelle
6

Erwägen Sie auch die Verwendung Array(). Aus dem Ruby Community Style Guide :

Verwenden Sie Array () anstelle der expliziten Array-Prüfung oder [* var], wenn Sie mit einer Variablen arbeiten, die Sie als Array behandeln möchten, aber nicht sicher sind, ob es sich um ein Array handelt.

# bad
paths = [paths] unless paths.is_a? Array
paths.each { |path| do_something(path) }

# bad (always creates a new Array instance)
[*paths].each { |path| do_something(path) }

# good (and a bit more readable)
Array(paths).each { |path| do_something(path) }
GuyPaddock
quelle
Dies wird zu unerwarteten Ergebnissen führen , wenn ein Hash vorbei , weil to_aauf jedes Argument hinzugefügt , um das neue Array, so genannt wird , Array({id: 100})kehrt[[:id, 100]]
brent