2010-02-24 13 views
12

Gegeben:Wie kann ich ein Vektorelement in Clojure aktualisieren?

(def my-vec [{:id 0 :a "foo" :b "bar"} {:id 1 :a "baz" :b "spam"} 
      {:id 2 :a "qux" :b "fred"}]) 

Wie kann ich aktualisieren idiomatisch * Der Artikel in my-vec mit :id=1 auf Werte haben :a="baz2" und :b="spam2"?

*: Ich weiß, dass ich my-vec nicht aktualisieren würde, aber wirklich einen neuen Vektor zurückgeben, der mit my-vec identisch ist, außer den Ersatzwerten.

Antwort

8

Karte eine Funktion über den Vektor von Karten, die entweder eine modifizierte Karte, wenn die Schlüssel nicht übereinstimmen erstellt oder verwendet das Original, wenn die Schlüssel nicht übereinstimmen dann das Ergebnis zurückdrehen in einen Vektor

(vec (map #(if (= (:id %) 1) 
      (assoc % :a "baz2" :b "spam2") 
      %))) 

Es ist möglich, dies prägnanter zu tun, obwohl dieser wirklich zeigt, wo das strukturelle Teilen auftritt.

+0

Macht die Syntax der # (%) -Funktion dies weniger klar? –

10

Wissen Sie im Voraus, dass die Karte mit ID == 1 die zweite Karte in Ihrem Vektor ist? Wenn ja:

user> (-> my-vec 
      (assoc-in [1 :a] "baz2") 
      (assoc-in [1 :b] "spam2")) 
[{:id 0, :a "foo", :b "bar"} {:id 1, :a "baz2", :b "spam2"} {:id 2, :a "qux", :b "fred"}] 

Wenn Sie Ihre Daten von ID für den Zugriff auf eine Menge, eine andere Idee ist, Ihren Vektor von Hash-Karten mit einer Hash-Karte von Hash-Maps ersetzt verkeilte auf :id. Dann können Sie leichter assoc-in egal in der Reihenfolge der Dinge.

user> (def new-my-vec (zipmap (map :id my-vec) my-vec)) 
#'user/new-my-vec 
user> new-my-vec 
{2 {:id 2, :a "qux", :b "fred"}, 1 {:id 1, :a "baz", :b "spam"}, 0 {:id 0, :a "foo", :b "bar"}} 
user> (-> new-my-vec 
      (assoc-in [1 :a] "baz2") 
      (assoc-in [1 :b] "spam2")) 
{2 {:id 2, :a "qux", :b "fred"}, 1 {:id 1, :a "baz2", :b "spam2"}, 0 {:id 0, :a "foo", :b "bar"}} 
+0

Hmm. Ich speichere es in einem Vektor, weil das, was ich gerade halte, ImageIcons von Spielkarten ist und die Vektorposition beim Zeichnen als Z-Reihenfolge fungiert. [{: id "8H": Bild ImageIcon} ...]. Aber ich könnte sie vielleicht in einer Karte speichern {{: id "8H": z-Reihenfolge 2: image ImageIcon} ...} und dann Graphik.Zeichnen sie, indem Sie sie nach ihrer sortierten: z-Reihenfolge ziehen. Danke, Brian, du bist ein Clojure-Monster. :) – scrotty

+4

'(update-in mein-vec [1] assoc: a" baz2 ": b" spam2 ") scheint viel sauberer. – amalloy

3

vielleicht einen Blick auf array-map nehmen wollen, die von einem Array und verkeilt durch den Index anstelle der Verwendung gesichert Karte erstellt: id?

Verwandte Themen