Попытка прочитать сильно вложенный код вызывает у меня головную боль.Хуже, когда ответом является что-то вроде «принудительного соответствия» с postwalk
, которое делает что-то вроде «наизнанку».Кроме того, использование partition-all
является пустой тратой, поскольку нам нужно отбросить любые пары с двумя не векторами.
Для меня наиболее естественным решением является простая нисходящая рекурсия.Единственная проблема заключается в том, что мы не знаем заранее, нужно ли нам удалить один или два элемента из заголовка входной последовательности.Таким образом, мы не можем использовать простой цикл for
или map
.
Итак, просто напишите его как прямую рекурсию и используйте if
, чтобы определить, потребляем ли мы 1 или 2 элемента изглава списка.
- Если второй элемент является значением, мы потребляем один элемент и добавляем
:dummy-value
, чтобы создать запись на карте. - Если 2-й элемент является вектором, мы рекурсивно используем его в качестве значения в записи на карте.
Код:
(ns tst.demo.core
(:require [clojure.walk :as walk] ))
(def data ["a" "b" ["c" ["t"] "d"] "e" ["f"] "g"])
(defn parse [data]
(loop [result {}
data data]
(if (empty? data)
(walk/keywordize-keys result)
(let [a (first data)
b (second data)]
(if (sequential? b)
(recur
(into result {a (parse b)})
(drop 2 data))
(recur
(into result {a :dummy-value})
(drop 1 data)))))))
с результатом:
(parse data) =>
{:a :dummy-value,
:b {:c {:t :dummy-value}, :d :dummy-value},
:e {:f :dummy-value},
:g :dummy-value}
Я добавил keywordize-keys
в конце, чтобы сделать результат немного более "Clojurey".