Reputation: 573
Not really sure what to call this, what I mean is I have a list of steps e.g.
[{:id 1 :layer :foo}
{:id 2 :layer :foo/bar}
{:id 3 :layer :foo}
{:id 4 :layer :bar/baz}
{:id 5 :layer :foo/bar}
{:id 6 :layer :foo/baz}
{:id 7 :layer :foo/baz}
{:id 8 :layer :foo/baz}
{:id 9 :layer :foo/baz}
{:id 10 :layer :foo}]
And I want to write a function that would return a nested sequence like so:
[{:layer :foo :steps [1 {:layer :foo/bar :steps [2]} 3]}
{:layer :bar :steps [{:layer :bar/baz :steps [4]}]}
{:layer :foo :steps [{:layer :foo/bar :steps [5]}
{:layer :foo/baz :steps [6 7 8 9]}
10]}]
Conceptually I understand how zippers might be used for something like this, but I don't know how to use them well enough to apply even after research. This is similar to what I'd use postwalk for, except there's a lot of next step previous step stuff regarding when to go up or down a layer.
Is there any alternative that's more idiomatic than a big ugly loop
?
Upvotes: 0
Views: 186
Reputation: 7568
If you changed your layers into vectors of keywords...
[{:id 1 :layer [:foo]}
{:id 2 :layer [:foo :bar]}
{:id 3 :layer [:foo]}
{:id 4 :layer [:bar :baz]}
{:id 5 :layer [:foo :bar]}
{:id 6 :layer [:foo :baz]}
{:id 7 :layer [:foo :baz]}
{:id 8 :layer [:foo :baz]}
{:id 9 :layer [:foo :baz]}
{:id 10 :layer [:foo]}]
... you could use something like this:
(defn solution
([object] (solution object 0 []))
([object level path-so-far]
(into [] (mapcat (fn [part]
(if-let [delimiter (-> part first :layer (nth level nil))]
[{:layer (conj path-so-far delimiter)
:steps (solution part
(inc level)
(conj path-so-far delimiter))}]
(mapv :id part))))
(partition-by (comp #(nth % level nil) :layer) object))))
With this result:
(solution [{:id 1 :layer [:foo]}
{:id 2 :layer [:foo :bar]}
{:id 3 :layer [:foo]}
{:id 4 :layer [:bar :baz]}
{:id 5 :layer [:foo :bar]}
{:id 6 :layer [:foo :baz]}
{:id 7 :layer [:foo :baz]}
{:id 8 :layer [:foo :baz]}
{:id 9 :layer [:foo :baz]}
{:id 10 :layer [:foo]}])
=>
[{:layer [:foo], :steps [1 {:layer [:foo :bar], :steps [2]} 3]}
{:layer [:bar], :steps [{:layer [:bar :baz], :steps [4]}]}
{:layer [:foo], :steps [{:layer [:foo :bar], :steps [5]} {:layer [:foo :baz], :steps [6 7 8 9]} 10]}]
Upvotes: 2