Ruby: Wählen Sie zwischen jedem, map, inject, each_with_index und each_w_object

8

Als ich vor vielen Jahren angefangen habe, Ruby zu schreiben, brauchte ich eine Weile, um den Unterschied zwischen each und map . Es wurde noch schlimmer, als ich all die anderen Enumerable und Array Methoden.

Mit Hilfe der offiziellen Dokumentation und vielen Fragen begann ich langsam zu verstehen, was diese Methoden getan haben.

Hier ist, was mich noch länger zu verstehen brauchte:

  • Warum sollte ich die eine oder andere Methode verwenden?
  • Gibt es irgendwelche Richtlinien?

Ich hoffe, dass diese Frage kein Duplikat ist: Ich interessiere mich mehr für das "Warum?" als das "Was?" oder "Wie?", und ich denke, es könnte Ruby Newcomern helfen.

    
Eric Duminil 07.11.2016, 16:04
quelle

2 Antworten

15

Eine Antwort tl; dr :

  

Wie wähle ich zwischen jedem, map, inject, each_with_index und jedem_with_object?

  • Verwenden Sie #each , wenn Sie eine "generische" Iteration wünschen und sich nicht um das Ergebnis kümmern. Beispiel - Sie haben Zahlen, Sie möchten den absoluten Wert jeder einzelnen Nummer ausgeben:

    %Vor%
  • Verwenden Sie #map , wenn Sie eine neue Liste wünschen, in der jedes Element durch Transformation der ursprünglichen Elemente gebildet wird. Beispiel - Sie haben Zahlen, Sie möchten ihre Quadrate erhalten:

    %Vor%
  • Verwenden Sie #inject , wenn Sie die gesamte Liste auf einen einzelnen Wert reduzieren möchten. Beispiel - Sie haben Nummern, Sie möchten ihre Summe erhalten:

    %Vor%
  • Verwenden Sie #each_with_index in derselben Situation wie #each , außer dass Sie auch den Index für jedes Element verwenden möchten:

    %Vor%
  • Die Verwendung von #each_with_object ist begrenzter. Der häufigste Fall ist, wenn Sie etwas ähnlich wie #inject benötigen, aber eine neue Sammlung (im Gegensatz zu einem einzelnen Wert) möchten, die keine direkte Zuordnung des Originals ist. Beispiel - Zahlenhistogramm (Frequenzen):

    %Vor%
ndn 07.11.2016, 16:26
quelle
3

Welches Objekt kann ich verwenden?

Zunächst sollte das Objekt, mit dem Sie arbeiten, ein Array sein, ein Hash , ein Set , ein Bereich oder jedes andere Objekt, das auf each reagiert. Wenn dies nicht der Fall ist, könnte es in etwas umgewandelt werden, das dies tut. Sie können each nicht direkt auf String zum Beispiel, weil Sie angeben müssen, ob Sie über jedes Byte, Zeichen oder jede Zeile iterieren möchten / p> %Vor%

Ich möchte etwas mit jedem Element berechnen, genau wie mit einer for-Schleife in C oder Java.

Wenn Sie über jedes Element iterieren, etwas damit machen und das ursprüngliche Objekt nicht verändern wollen, können Sie each . Bitte lesen Sie weiter, um zu wissen, ob Sie das wirklich sollten.

%Vor%

Dies ist die allgemeinste Iterationsmethode, und Sie könnten eine der anderen erwähnten Methoden damit schreiben. Wir werden tatsächlich, nur für pädagogische Zwecke. Wenn Sie in Ihrem Code ein ähnliches Muster entdecken, könnten Sie es wahrscheinlich durch die entsprechende Methode ersetzen.

Es ist grundsätzlich falsch, each zu verwenden, es ist jedoch fast nie die beste Wahl. Es ist ausführlich und nicht Ruby-ish.

Beachten Sie, dass each das ursprüngliche Objekt zurückgibt, aber das wird selten (nie?) benutzt. Die Logik findet innerhalb des Blocks statt und sollte das ursprüngliche Objekt nicht verändern.

Das einzige Mal, wenn ich each verwende, ist:

  • wenn keine andere Methode es tun würde. Je mehr ich über Ruby lerne, desto seltener passiert es.
  • wenn ich ein Skript für jemanden schreibe, der Ruby nicht kennt, Programmiererfahrung hat (z. B. C, Fortran, VBA) und meinen Code verstehen möchte.

Ich möchte ein Array aus meinem String / Hash / Set / Datei / Bereich / ActiveRecord :: Relation

bekommen

Rufen Sie einfach object.to_a auf.

%Vor%

Einige der unten beschriebenen Methoden (z. B. compact , < a href="https://ruby-doc.org/core-2.0/Array.html#method-i-uniq"> uniq ) sind nur für Arrays definiert.

Ich möchte ein modifiziertes Array basierend auf dem ursprünglichen Objekt erhalten.

Wenn Sie ein Array basierend auf dem ursprünglichen Objekt erhalten möchten, können Sie map . Das zurückgegebene Objekt hat die gleiche Größe wie das Original.

%Vor%

Das zurückgegebene Array wird das ursprüngliche Objekt nicht ersetzen.

Diese Methode ist sehr weit verbreitet. Es sollte der erste sein, den Sie nach each .

collect ist ein Synonym für %Co_de% . Stellen Sie sicher, dass nur eines von beiden in Ihren Projekten verwendet wird.

Ich möchte einen modifizierten Hash basierend auf dem ursprünglichen Hash erhalten.

Wenn Ihr ursprüngliches Objekt ein Hash ist, map wird sowieso ein Array zurückgeben. Wenn Sie einen Hash zurück möchten:

%Vor%

Ich möchte einige Elemente filtern.

Ich möchte nil Elemente entfernen

Sie können map aufrufen. Es wird ein neues Array ohne die Nil-Elemente zurückgegeben.

%Vor%

Ich möchte eine Logik schreiben, um festzustellen, ob ein Element im neuen Array

enthalten sein soll

Sie können compact oder select .

%Vor%

Ich möchte doppelte Elemente aus Ihrem Array entfernen

Sie können reject :

verwenden %Vor%

Ich möchte über alle Elemente iterieren, während ich von 0 bis n-1

zähle

Sie können uniq verwenden:

%Vor%

each_with_index gibt das ursprüngliche Objekt zurück.

>

Ich möchte über alle Elemente iterieren, während ich eine Variable während jeder Iteration setze und sie in der nächsten Iteration verwende.

Sie können each_with_index :

%Vor%

Gibt die Variable zurück, wie sie in der letzten Iteration definiert wurde.

inject ist ein Synonym. Wie bei map / collect, wähle ein Schlüsselwort und behalte es.

Ich möchte über alle Elemente iterieren und gleichzeitig eine Variable für jede Iteration verfügbar halten.

Sie können reduce verwenden:

%Vor%

Er gibt die Variable zurück, die durch die letzte Iteration geändert wurde. Beachten Sie, dass die Reihenfolge der beiden Blockvariablen im Vergleich zu each_with_object .

Wenn Ihre Variable ein Hash ist, sollten Sie diese Methode wahrscheinlich zum injizieren bevorzugen, weil inject 1 zurückgibt, und es würde eine weitere Zeile in Ihrem inject-Block erfordern, um einen Hash zurückzugeben.

Ich möchte etwas, das noch nicht erwähnt wurde.

Dann ist es wahrscheinlich in Ordnung, h["a"]=1 ;) zu verwenden.

Anmerkungen:

Es ist ein work in progress, und ich würde mich über Feedback freuen. Wenn es interessant genug ist und in eine Seite passt, kann ich daraus ein Flussdiagramm extrahieren.

    
Eric Duminil 07.11.2016 16:04
quelle

Tags und Links