scape
scape

Reputation: 707

Sequentially nest vectors/list in Clojure?

How could I convert this:

[a b c d e]

or this:

(e d c b a) ;(rseq [a b c d e])

to this:

[a[b[c[d[e]]]]]

I've been wracking my brain and I feel like there is a simple solution! :-\

Ultimately I want to do this:

[a b c d e]
[a b c x y]
[a b c d j k]

as this:

{a {b {c {d {e}
            {j {k}}
         {x {y}}}}

Which I think conj will help with

Upvotes: 1

Views: 117

Answers (2)

Michał Marczyk
Michał Marczyk

Reputation: 84331

(Update: added answer to the new question added in the edit below the answer to the original question.)

I've actually answered this very question in #clojure recently.

Here are two approaches: f is pretty much the spec directly transformed into code, which however creates a seq -- (next xs) -- which immediately gets poured into a new vector at each step; g is a much better version which only allocates objects which will actually occur in the output, plus a vector and the seq links to traverse it:

;; [1 2 3] -> [1 [2 [3]]]

;; naive, quadratic:
(defn f [xs]
  (if (next xs)
    [(first xs) (vec (f (next xs)))]
    (vec xs)))

;; only allocates output + 1 vector + a linear number of seq links,
;; linear overall:
(defn g [v]
  (reduce (fn [acc x]
            [x acc])
          [(peek v)]
          (rseq (pop v))))

NB. I'm overlooking the usual logarithmic factors arising from vector operations (so this is soft-O complexity).


As for producing a nested map, the above isn't particularly useful. Here's one approach:

(defn h
  ([v]
     (h nil v))
  ([m v]
     (assoc-in m v nil)))

(h [1 2 3 4])
;= {1 {2 {3 {4 nil}}}}

(def data
  '[[a b c d e]
    [a b c x y]
    [a b c d j k]])

(reduce h {} data)
;= {a {b {c {x {y nil}, d {j {k nil}, e nil}}}}}

I'm using nil as a "terminator", since {y} (as currently found in the answer text) is not a well-formed literal. true might be a more convenient choice if you plan to call these maps as functions to check for presence of keys.

Upvotes: 4

Display Name
Display Name

Reputation: 8128

Simpler solution here (using destructuring and non-tail recursion):

http://ideone.com/qchXZC

(defn wrap
  ([[a & as]]
    (if-let [[b & cs] as]
      [a (wrap as)]
    [a])))

Upvotes: 4

Related Questions