Chris Edwards
Chris Edwards

Reputation: 1558

Clojure array of maps

I am trying to model this kind of data in Clojure

name: foo    data: bar
name: stack  data: overflow
name: tess   data: ting

I thought about using a map, but you can't have duplicated keys in there so that wouldn't work.

Is it possible to have an array of maps, similar to:

[{name: foo,    data: bar} 
{name: stack,  data: overflow} 
{name: tess,   data: ting}]

if it is, how would you access the data. for example, how would you access data: overflow

would you have to use a nested get statement?

Upvotes: 1

Views: 953

Answers (2)

coredump
coredump

Reputation: 38809

Maybe I am missing something, but it looks as-if you are reinventing a map where instead of keys and values you want to have names and data. For example, the following is sufficient to model your map:

(get {"foo" "bar" "stack" "overflow" "tess" "ting"} "stack")
=> "overflow"

Now, if your data is more complex, you can certainly store a map under an certain key. In other words, you build a map where the key is the name associated with each data. Suppose you have a vector of such things:

(def data [{:name "foo"   :data "bar"} 
           {:name "stack" :data "overflow"} 
           {:name "tess"  :data "ting"}])

In order to have the corresponding map, you can do:

(reduce (fn [m d] (assoc m (:name d) d)) {} data)

... which gives:

{"tess"  {:name "tess" , :data "ting"}, 
 "stack" {:name "stack", :data "overflow"}, 
 "foo"   {:name "foo"  , :data "bar"}}

Upvotes: 4

zarkone
zarkone

Reputation: 1355

First, {:name "foo" :data "overflow"}, this is EDN, not JSON;

Second, yes, it's ok to (def map-array [{:name "foo"} {:name "bar"}])

To get access to fields you can use get and get-in: https://clojuredocs.org/clojure.core/get-in.

(get-in map-array [1 :name])
=> "bar"

You can also use filter function in such way:

(first (filter #(= "foo" (:name %)) map-array))
=> {:name "foo"}

EDIT: If you want to get rid of filter to and get constant access time to your maps, you should use some kind of uniq ID:

(def map-array {:id1 {:name "foo"}
                :id2 {:name "bar"}})
(get-in map-array [:id1 :name])
=> "foo"

;; using threading macro and keyword special power:
(-> map-array :id2 :name)
=> "bar"

Upvotes: 2

Related Questions