Search code examples
clojuremaps

How can I generate a list from a nested map in Clojure?


I have this atom:

(def test (atom {:james {:friends [:lucy :john :daisy]},
                 :lucy {:friends [:james :daisy]},
                 :daisy {:friends [:james :lucy]},
                 :john {:friends [:james]}}))

Giving :james as an argument, I need to iterate over its :friends and put every friend of :james friends in a list. The result must be something like this:

(:james :daisy :james :james :lucy)

This is my best effort so far:

(def user :james)

(def test2 (atom []))

(defn access
  [user]
  (get-in @test [user :friends]))

(doseq [connection (access user)]
  (swap! test2 concat (access connection)))

@test2

I don't think that using another atom (test2) is the most idiomatic way to do it.


Solution

  • True, you don't need an intermediate atom.

    (def users (atom {:james {:friends [:lucy :john :daisy]},
                     :lucy   {:friends [:james :daisy]},
                     :daisy  {:friends [:james :lucy]},
                     :john   {:friends [:james]}}))
    
    (defn friends [dict level users]
        (-> (fn [users] (mapcat #(get-in dict [% :friends]) users))
            (iterate users)
            (nth level)))
    
    (friends @users 2 [:james])