Ich entdeckte vor kurzem die Specter-Bibliothek, die Datenstruktur Navigation und Transformation Funktionen bietet und in Clojure geschrieben ist.Wählen Sie Elemente aus einer verschachtelten Struktur, die eine Bedingung in Clojure
Die Implementierung einiger APIs als Lernübung schien eine gute Idee zu sein. Specter implementiert eine API eine Funktion und eine verschachtelte Struktur als Argument und gibt einen Vektor von Elementen aus der verschachtelten Struktur nehmen, die die Funktion wie unten erfüllt:
(select (walker number?) [1 :a {:b 2}])
=>[1 2]
Unten ist mein Versuch, eine Funktion bei der Umsetzung mit ähnlichen API:
(defn select-walker [afn ds]
(vec (if (and (coll? ds) (not-empty ds))
(concat (select-walker afn (first ds))
(select-walker afn (rest ds)))
(if (afn ds) [ds]))))
(select-walker number? [1 :a {:b 2}])
=>[1 2]
ich versucht habe, die Umsetzung select-walker
unter Verwendung von list comprehension, looping und unter Verwendung von cons und conj. In allen diesen Fällen der Rückgabewert war eine verschachtelte Liste anstelle eines flachen Vektors von Elementen.
Doch meine Implementierung scheint nicht wie idiomatische Clojure und hat eine geringe Zeit und Raum Komplexität.
(time (dotimes [_ 1000] (select (walker number?) (range 100))))
"Elapsed time: 19.445396 msecs"
(time (dotimes [_ 1000] (select-walker number? (range 100))))
"Elapsed time: 237.000334 msecs"
Beachten Sie, dass meine Implementierung ist etwa 12-mal langsamer als Spectre-Implementierung.
Ich habe drei Fragen zur Umsetzung von select-walker
.
- Ist eine tail-rekursive Implementierung von
select-walker
möglich? - Kann
select-walker
in idiomatischer Clojure geschrieben werden? - Alle Hinweise zu machen
select-walker
führen schneller?
Danke. Ich mochte die Art und Weise, wie "select-walker-rec" durch die verschachtelten ds recursiert. Ähnlich wie bei der ersten Traversierung. – ardsrk