Wie bekomme ich die verschachtelten Schlüssel einer Karte in clojure?

7

wenn meine Struktur

ist %Vor%

Ich möchte eine Funktion namens keys-in erhalten, die etwas wie folgt zurückgibt:

%Vor%

Also kann ich etwas tun wie:

(not-any? nil? (Karte # (meine-andere-Karte% 1) (Schlüssel-in meine-Karte)))

Damit kann ich sicher sein, dass my-other-map die gleichen Schlüssel wie my-map

hat     
David Rz Ayala 14.02.2014, 00:51
quelle

10 Antworten

11
%Vor%     
Alex Miller 14.02.2014, 02:35
quelle
7
%Vor%     
amalloy 14.02.2014 02:19
quelle
4

Obligatorische Reißverschlüsse Version

%Vor%     
A. Webb 14.02.2014 03:22
quelle
2

Sie können dies relativ einfach mit clojure.zip oder tree-seq erstellen, obwohl ich die prismatic.schema Bibliothek zur Überprüfung sehr bevorzuge die Struktur von verschachtelten Karten

%Vor%     
Arthur Ulfeldt 14.02.2014 02:11
quelle
2

Wenn Sie kein faules Ergebnis benötigen und nur schnell sein wollen, versuchen Sie reduce-kv .

%Vor%

Wenn Sie auch Vektorindizes unterstützen möchten (wie bei get-in oder update-in ), testen Sie mit associative? anstelle von map? . Wenn Sie Zwischenpfade möchten, können Sie diese auch verbinden. Hier ist eine Variante:

%Vor%     
miner49r 18.07.2016 18:35
quelle
2

Eine ähnliche Frage wurde von den aktuellen Lösungen nicht erfüllt:

"Naive" rekursive Vorgehensweise

%Vor%     
Laurent 10.03.2016 21:18
quelle
1

Diese Antwort von mir ist nur um zu veranschaulichen, wie es NICHT zu tun ist, da es noch prozedural ist.

%Vor%     
David Rz Ayala 14.02.2014 02:53
quelle
1

Hier ist eine Implementierung, die alle Schlüssel (nicht nur die Terminal-Schlüssel) basierend auf lazy-seq zurückgibt:

%Vor%     
Aaron Cummings 16.11.2015 05:36
quelle
1

Hier sind Lösungen (ohne Zwischenpfade) mit Spectre . Sie stammen von Nathan Marz, dem Autor von Spectre, aus einer Konversation im Spectre Slack Channel (mit seiner Erlaubnis). Ich beanspruche diese Definitionen nicht.

Einfache Version:

%Vor%

Effizientere Version:

%Vor%

Meine informelle Erklärung, was in diesen Definitionen passiert:

Da in der einfachen Version das Top-Level-Argument eine Map ist, übergibt if-path map? es an die erste Sammlung von Navigatoren in Klammern. Diese beginnen mit ALL , was hier heißt, den Rest für jedes Element in der Map zu machen. Dann sagt MapEntry für jedes (collect-one FIRST) in der Map, dass sein erstes Element (key) dem Ergebnis der letzten Übergabe seines letzten Elements (val) an if-path hinzugefügt wird. p wurde durch recursive-path als Verweis auf denselben recursive-path -Ausdruck gebunden. Durch diesen Prozess gelangen wir schließlich zu einer Nicht-Map. Gebe es zurück und beende die Verarbeitung in diesem Zweig; das ist, was STAY bedeutet. Diese letzte Sache ist jedoch nicht einer der Schlüssel; es ist das Terminal val. Also enden wir mit den Blattwerten in jeder Sequenz. Um sie zu entfernen, maskiere butlast über das gesamte Ergebnis.

Die zweite Version vermeidet diesen letzten Schritt, indem sie nur in den Wert in MapEntry rekurriert, wenn dieses val selbst eine Karte ist. Das macht die innere if-path : [LAST map?] erhält das letzte Element, d. H. Den Wert des aktuellen MapEntry , der von ALL generiert wurde, und übergibt ihn an map? .

Ich habe Criterium verwendet, um alle Schlüsselpfadfunktionen auf dieser Seite zu testen, die keine Zwischenpfade zurückliefern, plus einen von geräuschverursachenden, der Teil eines Beantworte eine andere Frage . Für eine 3-Level-Karte mit 3 Tasten pro Level und für eine 6-Level-Karte mit 6 Tasten pro Level haben die Version von miner49r und die zweite, schnellere Spectre-Version ähnliche Geschwindigkeiten und sind viel schneller als alle anderen Versionen.

Timings auf einer 3-Level, 3 Schlüssel pro Level (27 Pfade) map, in der Reihenfolge:

  • miner49rs: 29,235649 μs
  • N. Marz 'zweites Spectre: 30.590085 μs
  • N. Marz 'erster Spectre: 62,840230 μs
  • amalloy's: 75.740468 μs
  • noisesmith's (aus der anderen Frage): 87.693425 μs
  • AWebbs: 162.281035 μs
  • AlexMillers (ohne vec ): 243.756275 μs

Timings auf einer 6-Level, 6 Schlüssel pro Level (6 ^ 6 = 46656 Pfade) Karte in der Reihenfolge:

  • N. Marz 'zweiter Spectre: 34,435956 ms
  • miner49rs: 37.897345 ms
  • N. Marz 'erster Spectre: 119.600975 ms
  • NoiseMith: 180.448860 ms
  • amalloy's: 191.718783 ms
  • AWebbs: 193.172784 ms
  • AlexMillers (ohne vec ): 839.266448 ms

Alle Aufrufe wurden in doall eingeschlossen, damit faule Ergebnisse erzielt werden. Da ich doall ing war, habe ich vec wrapper in Alex Millers Definition herausgenommen. Ausführliche Informationen zu den Timings finden Sie hier . Der Testcode ist hier .

(Die einfache Spectre-Version ist langsamer als die schnellere Version, da map butlast zum Entfernen der Blattwerte verwendet wird. Wenn dieser Schritt entfernt wird, entsprechen die Zeiten der einfachen Spectre-Definition denen der zweiten Definition. )

    
Mars 17.03.2017 20:08
quelle
0

Ich arbeite an etwas ähnlichem für ein persönliches Projekt und das ist meine naive Umsetzung:

%Vor%

Benutze es aus dem repl:

%Vor%

Schicker Weg:

%Vor%     
user2762156 26.01.2018 22:24
quelle