aceminer
aceminer

Reputation: 4295

Updating records with a vector

How do i update records with its elements

(pprint records)
({:Name "John" :Age 12 :Index 123 :Class_Index}
 {:Name "Joe" :Age 13 :Index 3 :Class_Index}
 {:Name "Jon" :Age 14 :Index 4 :Class_Index})

How do i write a function such that the class_index is updated based on the age + index. At the same time can records be updated such that after running the function the output would be this

(pprint records)
({:Name "John" :Age 12 :Index 123 :Class_Index 135}
 {:Name "Joe" :Age 13 :Index 3 :Class_Index 16}
 {:Name "Jon" :Age 14 :Index 4 :Class_Index 18})

However, i am unable to manually type out all the elements of records as it would contain too much rows. Can the function in your answer still be used? The pprint is simply just for illustration. In actual fact my record would contain many elements instead.

In the sense (def records (atom [records])) or would i have to iterate through the rows which would take up too much memory. Is there a more efficient way of doing this.

Upvotes: 2

Views: 464

Answers (2)

Matt
Matt

Reputation: 17629

Keep in mind, that in the context of Clojure, records are a way of structuring your maps (I guess you meant records from your database). Concerning your question:

    ; The database
(def people [
  {:Name "John" :Age 12 :Index 123}
  {:Name "Joe" :Age 13 :Index 3}
  {:Name "Jon" :Age 14 :Index 4}])

; Calculates the class index for a person and returns the updated person
(defn class-index [{:keys [Age Index] :as person}]
    (assoc person :Class_Index (+ Age Index)))

; Calculate the class index for all people
(pprint (map class-index people))

; Output
; ({:Name "John", :Age 12, :Class_Index 135, :Index 123}
; {:Name "Joe", :Age 13, :Class_Index 16, :Index 3}
; {:Name "Jon", :Age 14, :Class_Index 18, :Index 4})

Upvotes: 0

mobyte
mobyte

Reputation: 3752

If you're always going to update records at once

(def records (atom [(->Record "John" 12 123 nil)
                    (->Record "Joe" 13 3 nil)
                    (->Record "Jon" 14 4 nil)]))

(reset! records (map #(assoc % :Class_Index (+ (:Age %) (:Index %)))
                     @records))

(pprint records)
-> #<Atom@131bf42: 
     ({:Name "John", :Age 12, :Index 123, :Class_Index 135}
      {:Name "Joe", :Age 13, :Index 3, :Class_Index 16}
      {:Name "Jon", :Age 14, :Index 4, :Class_Index 18})>

Otherwise

(def records [(ref (->Record "John" 12 123 nil))
              (ref (->Record "Joe" 13 3 nil))
              (ref (->Record "Jon" 14 4 nil))])

(dosync (doseq [record records]
          (alter record #(assoc % :Class_Index (+ (:Age %) (:Index %))))))

(pprint records)
-> [#<Ref@178f7a8: {:Name "John", :Age 12, :Index 123, :Class_Index 135}>
    #<Ref@129617b: {:Name "Joe", :Age 13, :Index 3, :Class_Index 16}>
    #<Ref@ac9126: {:Name "Jon", :Age 14, :Index 4, :Class_Index 18}>]

Update. If there are many elements in collection then it's better to use clojure maps instead of record objects. Just replace records definition with maps

(def records (atom [{:Name "John", :Age 12, :Index 123, :Class_Index nil}
                    {:Name "Joe", :Age 13, :Index 3, :Class_Index nil}
                    {:Name "Jon", :Age 14, :Index 4, :Class_Index nil}]))

or if there is the source of items

(def records (atom (source-fn ...)))

In this case there is no memory overhead. Rest of code would be the same.

Upvotes: 2

Related Questions