1

In clojure, how can I turn a nested map like this:

{"1" {"1.1" {"1.1.1" {}
             "1.1.2" {}}
      "1.2" {}}
 "2" {"2.1" {}
      "2.2" {}
      "2.3" {}}}

Into this:

("1" "1.1" "1.1.1" "1.1.2" "1.2" "2" "2.1" "2.2" "2.3")

2 Answers2

3

Here is a straightforward iterative solution (using loop and recur):

(defn flatten-map [m]
  (loop [in m out []]
    (if-let [[[k v] & ts] (seq in)]
      (recur (concat v ts)
             (conj out k))
      out)))

And a "fancy" one (using tree-seq function)

(defn flatten-map [m]
  (->> [nil m]
       (tree-seq sequential? second)
       (drop 1)
       (map first)))
Leonid Beschastny
  • 50,364
  • 10
  • 118
  • 122
1

Here's a recursive solution:

(defn flatten-map [m]
  (flatten
    (for [[k v] m]
      (cons k (flatten-map v)))))
  • 2
    It's a very bad idea to use `flatten` here. You should use something non-recursive instead, e.g. `apply concat`. – Leonid Beschastny Mar 15 '15 at 21:05
  • Can you please explain why? (Not disagreeing with you) –  Mar 15 '15 at 21:06
  • Recursion is not inherently bad. Does this particular case incur significant overhead or otherwise harm performance? If so, I can see how loop/recur would help out. –  Mar 15 '15 at 21:10
  • I don't like `flatten` because it adds unnecessary complexity since you only need a one-level flattening here. – Leonid Beschastny Mar 15 '15 at 21:13
  • Though, recursion is always slower than iteration and could cause a stack overflow. But recursive solutions are usually much simpler and easier to understand. – Leonid Beschastny Mar 15 '15 at 21:15
  • 1
    `flatten` may also produce an unwanted result. For example, try flattening `{1 {[1 1] {} [1 2] {}}}` with your function. Instead of expected `[1 [1 1] [1 2]]` your function will produce a flattened `[1 1 1 1 2]`. – Leonid Beschastny Mar 15 '15 at 21:24
  • You may also want to look at this question: [Clojure: Why is flatten “the wrong thing to use”](http://stackoverflow.com/q/25182904/1202461). – Leonid Beschastny Mar 15 '15 at 21:25
  • 1
    What I'm trying to say is that you should use `flatten` only when you want to flatten some **nested** data structure of unknown depth. But there are much better ways to perform one-level flattening. – Leonid Beschastny Mar 15 '15 at 21:34