Ein Blick hinter die Kulissen von Map, Filter und Reduce in Swift

Eine Funktion nimmt eine Eingabe entgegen, macht etwas damit und erstellt eine Ausgabe. Eine Funktion hat eine Signatur und einen Körper. Wenn Sie einer Funktion dieselbe Eingabe geben, erhalten Sie immer dieselbe Ausgabe. Das ist kurz eine Definition für die Funktion .

Jetzt werden wir mehr über Funktionen sprechen, indem wir sie genauer betrachten. Wir werden Funktionen höherer Ordnung in Swift untersuchen. Eine Funktion, die eine andere Funktion als Eingabe verwendet oder eine Funktion zurückgibt, wird aufgerufeneine Funktion höherer Ordnung .

In Swift spielen wir mit Karte, filtern, reduzieren jeden Tag. Wenn wir diese Funktionen verwenden, scheint es wie Magie. Zu diesem Zeitpunkt haben Sie möglicherweise keine Vorstellung davon, was sich hinter den Kulissen abspielt. Zuordnen, Filtern und Reduzieren der Arbeit anhand der Ideen und Ansätze der funktionalen Programmierung. Obwohl Swift keine reine funktionale Sprache ist, können Sie damit funktionale Dinge tun.

Schauen wir uns nun nacheinander an, was für sie im Hintergrund passiert. Zuerst werden wir die Basisversionen dieser Funktionen für bestimmte Datentypen implementieren, dann werden wir versuchen, eine generische Version zu implementieren.

Kartenfunktion

Angenommen, wir haben ein Array von Ganzzahlen und müssen eine Funktion schreiben, die ein neues Array zurückgibt, nachdem jedem Element des ursprünglichen Arrays ein Delta-Wert hinzugefügt wurde. Wir können leicht eine Funktion dafür schreiben, indem wir eine einfache for-Schleife wie folgt verwenden:

Jetzt brauchen wir eine andere Funktion, die ein neues Array zurückgibt, indem jedes Element des ursprünglichen Arrays verdoppelt wird. Dafür können wir es wie folgt implementieren:

Wenn wir uns die beiden oben genannten Funktionen ansehen, können wir feststellen, dass sie im Grunde dasselbe tun. Nur die Funktionalität innerhalb der for-Schleife ist unterschiedlich. Beide verwenden ein Integer- Array als Eingabe, transformieren jedes Element mithilfe einer for-Schleife und geben ein neues Array zurück. Die Hauptsache ist also, jedes Element in etwas Neues zu verwandeln.

Da Swift Funktionen höherer Ordnung unterstützt, können wir eine Funktion schreiben, die ein Array von Ganzzahlen verwendet, die Funktion als Eingabe transformiert und ein neues Array zurückgibt, indem wir die Transformationsfunktion auf jedes Element des ursprünglichen Arrays anwenden.

Trotzdem gibt es ein Problem mit dem oben genannten: Es wird nur ein ganzzahliges Array zurückgegeben. Wenn wir beispielsweise das Eingabe-Integer-Array in ein String-Array konvertieren müssen, können wir dies mit dieser Funktion nicht tun. Dazu müssen wir eine generische Funktion schreiben, die für jeden Typ funktioniert.

Wir können eine generische Funktion in einer Array-Erweiterung wie folgt implementieren:

  1. Deklarieren Sie eine Map-Funktion in der Array-Erweiterung, die mit einem generischen Typ T funktioniert .
  2. Die Funktion übernimmt eine Funktion vom Typ (Element) -> ; T als Eingang
  3. Deklarieren Sie ein leeres Ergebnisarray, das die Daten des T- Typs in der Funktion enthält.
  4. Implementieren Sie eine for-Schleife, die sich selbst iteriert, und rufen Sie die Transformationsfunktion auf, um das Element in den Typ T zu konvertieren
  5. Fügen Sie den konvertierten Wert in das resultierende Array ein

So funktioniert die Kartenfunktion in Swift. Wenn wir die Karte implementieren müssenFunktion , dann würden wir es wie oben implementieren. Im Grunde genommen lässt es keine Magie in einem Array geschehen - wir hätten die Funktion leicht selbst definieren können.

Filterfunktion

Angenommen, wir haben ein Array von Ganzzahlen und möchten nur die geraden Zahlen im Array behalten. Wir können dies implementieren, indem wir eine einfache for-Schleife verwenden:

Angenommen, wir haben ein Array von Zeichenfolgen, die Klassendateinamen eines Projekts darstellen, und wir möchten nur die beibehalten . schnelle Dateien. Dies kann auch mit einer einzelnen Schleife wie folgt erfolgen:

Wenn wir uns die Implementierung der beiden oben genannten Funktionen genau ansehen, können wir verstehen, dass sie im Grunde dasselbe tun - nur der Datentyp ist für die beiden Arrays unterschiedlich. Wir können dies verallgemeinern, indem wir eine generische Filterfunktion implementieren, die ein Array und eine Funktion als Eingabe verwendet und abhängig von der Ausgabe der includeElement- Funktion entscheidet, ob das Element in das resultierende Array eingefügt wird .

Funktion reduzieren

Angenommen, wir haben ein Array von Ganzzahlen und möchten zwei Funktionen implementieren, die die Summe und das Produkt der Elemente zurückgeben. Wir können dies implementieren, indem wir eine einfache for-Schleife verwenden:

Anstatt ein Array von Ganzzahlen zu haben, nehmen wir an, wir haben ein Array von Zeichenfolgen und möchten alle Elemente im Array verketten:

Alle drei Funktionen machen im Grunde das Gleiche. Sie nehmen ein Array als Eingabe, initialisieren eine resultierende Variable, iterieren über das Array und aktualisieren die resultierende Variable.

Von hier aus können wir eine generische Funktion implementieren, die für alle funktionieren sollte. Dazu benötigen wir den Anfangswert der resultierenden Variablen und die Funktion, um diese Variable in jeder Iteration zu aktualisieren.

So können wir die generische Funktion mit der folgenden Definition implementieren:

Die obige Implementierung ist generisch für jedes Eingabearray vom Typ [Element]. Es wird ein Ergebnis vom Typ T berechnet . Um zu arbeiten, benötigt es einen Anfangswert vom Typ T , um einer resultierenden Variablen zugewiesen zu werden. Dann benötigt es eine Funktion vom Typ (T, Element) -> T, die in jeder Iteration innerhalb der for-Schleife verwendet wird, um die resultierende Variable zu aktualisieren.

Danke fürs Lesen!