(defn do-to-map [amap keyseq f]
(reduce #(assoc %1 %2 (f (%1 %2))) amap keyseq))
Aufteilung:
Es hilft von innen nach außen, es zu betrachten. In Clojure verhalten sich Hash-Maps wie Funktionen; Wenn Sie sie wie eine Funktion mit einem Schlüssel als Argument aufrufen, wird der Wert zurückgegeben, der diesem Schlüssel zugeordnet ist. So einen einzelnen Schlüssel gegeben, kann der aktuelle Wert für diesen Schlüssel werden über erhalten:
(some-map some-key)
Wir alten Werte nehmen wollen, und sie auf neue Werte ändern, indem Sie eine Funktion f
sie auffordern. So einen Schlüssel gegeben, wird der neue Wert sein:
(f (some-map some-key))
Wir diesen neuen Wert mit diesem Schlüssel zuordnen mögen in unserer Hash-Karte, den alten Wert „ersetzt“. Dies ist, was assoc
tut:
(assoc some-map some-key (f (some-map some-key)))
(„Ersetzen“ ist in Panik Anführungszeichen, weil wir nicht ein einziges Hash-Map-Objekt mutieren, wir neue, unveränderlich, veränderte Hash-Karte sind wiederkehrende Objekte jedes Mal wir nennen assoc
. Diese immer noch schnell und effizient in Clojure ist da Hash-Karten sind persistent und Struktur teilen, wenn Sie assoc
sie.)
wir brauchen immer wieder assoc
neue Werte auf unserer Karte zu, ein Schlüssel zu einem Zeitpunkt. Wir brauchen also eine Art Schleifenkonstrukt. Wir wollen mit unserer ursprünglichen Hash-Map und einem einzigen Schlüssel beginnen und dann den Wert für diesen Schlüssel "updaten". Dann nehmen wir diese neue Hash-Map und den nächsten Schlüssel und "aktualisieren" den Wert für den nächsten Schlüssel. Und wir wiederholen dies für jeden Schlüssel einzeln und geben schließlich die Hash-Karte zurück, die wir "angesammelt" haben. Dies ist, was reduce
tut.
- Das erste Argument für
reduce
ist eine Funktion, die zwei Argumente nimmt: ein „Akkumulator“ Wert, der der Wert wir immer halten „Aktualisierung“ ist; und ein einzelnes Argument, das in einer Iteration verwendet wird, um einen Teil des Akkumulierens auszuführen. Das zweite Argument zu reduce
ist der Anfangswert, der als erstes Argument an dieses fn
übergeben wird.
- Das dritte Argument zu
reduce
ist eine Sammlung von Argumenten, die als zweites Argument zu diesem fn
nacheinander übergeben werden.
So:
(reduce fn-to-update-values-in-our-map
initial-value-of-our-map
collection-of-keys)
fn-to-update-values-in-our-map
ist nur die assoc
Anweisung von oben, in einer anonymen Funktion eingewickelt:
(fn [map-so-far some-key] (assoc map-so-far some-key (f (map-so-far some-key))))
So ist es in reduce
Verstopfen:
(reduce (fn [map-so-far some-key] (assoc map-so-far some-key (f (map-so-far some-key))))
amap
keyseq)
Im Clojure, es gibt eine Abkürzung für das Schreiben anonymer Funktionen: #(...)
ist eine anonyme fn
bestehend aus einem einzigen Formular, in dem %1
an das erste Argument der anonymen Funktion gebunden ist, %2
an die zweite usw. So kann unsere fn
von oben geschrieben werden äquivalent als:
#(assoc %1 %2 (f (%1 %2)))
Das gibt uns:
(reduce #(assoc %1 %2 (f (%1 %2))) amap keyseq)
Würde es Ihnen etwas ausmachen, eine Aussage nach Aussage Beschreibung für uns neu zu Clojure geben? –
Hoffe, dass hilft. –
Das # (...) Notation ist genial. Gute Antwort! –