2012-05-25 14 views
29

Wie überprüfe ich, ob ein Objekt in Ruby iterierbar ist?Wie überprüft man, ob ein Objekt in Ruby iterierbar ist?

Das heißt, möchte ich eine Methode, die sauber überprüft, ob ein Objekt iterable ist, etwa so:

def is_iterable(my_object) 
    .. 
end 

Ich bin wirklich nicht sicher, wo auf diesem kurzen explizit Namensklassen aus dem Verfahren beginnen .

Bearbeiten: Für meine Zwecke sagen wir iterable ist etwas, was Sie tun können.

+2

definieren „iterable“ zu antworten. –

+0

@SergioTulentsev Aktualisierung überprüfen. – varatis

+0

Überprüfen Sie meine Antwort :) –

Antwort

40

For my purposes, let's say iterable is something you can do .each to.

können Sie nur fragen, ob das Objekt diese Methode hat

def iterable?(object) 
    object.respond_to? :each 
end 
+8

Dies funktioniert nicht in allen Fällen. 'nil..nil' ist ein Range-Objekt und antwortet auf' each', ist jedoch nicht iterierbar und löst 'TypeError: kann nicht von NilClass' durchlaufen werden, wenn versucht wird, zu iterieren. Ich habe das gerade in einem Projekt mit einem Datumsbereich eingegeben, der es gegen falsche Benutzereingaben wie nichts oder zufällige Strings usw. testet. –

+0

Das ist interessant, danke für die Erwähnung :) –

+0

Andere Objekte könnten Methode #Each, die bessere Antwort (unten) wäre zu sehen, ob es Enumerable ist. – saneshark

9

Es gibt eine Reihe von Möglichkeiten, dies zu tun, abhängig von Ihren größeren Zielen und was Sie brauchen, mit dem Ergebnis zu tun.

  1. Wenn Sie nur Ente eingeben verwenden möchten, um zu sehen, ob das Objekt auf #each reagiert, dann können Sie nur das Objekt fragen, ob es ein solches Verfahren hat.

    my_object.respond_to? :each 
    
  2. Wenn Sie herausfinden wollen, ob das Objekt in der Enumerable-Klasse mischt, können Sie die Klasse für die Aufnahme überprüfen.

    my_object.class.include? Enumerable 
    
  3. Wenn Sie eine Liste aller Vorfahren und Mixins wollen, möchten Sie die #ancestors Methode. Zum Beispiel, um zu sehen, ob my_object erbt von der Enumerable-Klasse, können Sie aufrufen:

    my_object = [] 
    my_object.class.ancestors 
    => [Array, Enumerable, Object, PP::ObjectMixin, Kernel, BasicObject] 
    
    my_object.class.ancestors.include? Enumerable 
    => true 
    
+1

Warum verwenden Sie 'my_object.class.include? Enumerable' statt 'my_object.is_a? Enumerierbar? – dbenhur

+0

@dbenhur Semantische Klarheit. Die Ergebnisse sind im Allgemeinen die gleichen. –

+0

Anstatt auf Vorfahren zu schauen, können Sie auch so überprüfen: 'my_object.class mbillard

1

Im allgemeinen Fall können Sie überprüfen, ob each Methode definiert ist, oder wenn Enumerable Modul ist in Objektklasse enthalten :

my_object.class.include? Enumerable 
41

Sie haben bereits einige Antworten, aber hier sind zwei weitere Möglichkeiten, Object#is_a?/Object#kind_of? und Module#===:

[].is_a? Enumerable #=> true 
    "".is_a? Enumerable #=> false 

    Enumerable === [] #=> true 
    Enumerable === "" #=> false 
+0

guten Punkt! 432 – fl00r

1

Da Range auf each reagiert, auch wenn es nicht durchsuchbar Sie speziell müssen prüfen, ob die Reichweite der Elemente zu succ

def iterable?(object) 
    return object.begin.respond_to? :succ if object.kind_of? Range 
    object.respond_to? :each 
end 
Verwandte Themen