This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-05-22
Channels
- # aws (5)
- # bangalore-clj (3)
- # beginners (84)
- # boot (31)
- # carry (1)
- # cider (6)
- # cljsrn (7)
- # clojure (188)
- # clojure-conj (1)
- # clojure-dev (3)
- # clojure-dusseldorf (8)
- # clojure-greece (10)
- # clojure-italy (7)
- # clojure-nl (3)
- # clojure-russia (45)
- # clojure-spec (5)
- # clojure-uk (64)
- # clojurescript (83)
- # clr (9)
- # core-async (45)
- # cursive (55)
- # datomic (8)
- # devops (1)
- # emacs (7)
- # graphql (1)
- # hoplon (3)
- # jobs (1)
- # jobs-discuss (37)
- # lein-figwheel (3)
- # leiningen (4)
- # luminus (6)
- # off-topic (5)
- # om (2)
- # onyx (33)
- # pedestal (13)
- # re-frame (9)
- # reagent (28)
- # rum (15)
- # specter (4)
- # unrepl (38)
- # vim (3)
Господа, а вот расскажите, что мне делать. Есть у меня дерево {:dirs {"a" <..> "b" <..>} :files {"c" <..> "d" <..>}}
где внутри :dirs
такие же узлы, а внутри :files
листья. И есть у меня путь ["a" "b" "c" "file"]
внутри такого дерева. Хочу я сделать операцию "добавить путь в дерево" с созданием промежуточных директорий, если их там нет.
Руками попытался рекурсивную функцию сделать -- получился какой-то ужас с ручным (conj ..)
на каждом шагу того, что поменялось.
ага, как раз для зипперов задача. Правда я редактировал всего один раз дерево, что-то простое совсем делал, почти все время тока на чтение работал
ну и кста счас думаю про ручную функцию, там же сразу можно ее свести заместо >с созданием промежуточных директорий, если их там нет упросить до >создать 1 уровень ниже если не существует что должно быть проще уже
а уж из пути проитерировать и дернуть эту функцию N раз не должно быть сложно через обычный loop/reduce. Или я что-то упускаю?
а там же надо будет находить опять куда мы в прошлый раз добавили ноду и откуда опять начать копать, трекать в каком мы сейчас месте… oh shit… it’s a zipper! 😄
да там же свой кастомный зиппер то сделать как два пальца как функцию вызвать
ты думаю смотрел https://clojuredocs.org/clojure.zip/zipper
а ну окей, свое то милее конечно 🙂
У меня несколько операций вида "поколдовать так над узлом в дереве, а потом по-другому над листиком".
прям как скопировал из описания зиппера, но да ладно 🙂 Ты потом чиркани сюда как решил в итоге, любопытно
@dottedmag а specter смотрел? оно продаётся как операции-типа-update-in/get-in только лучше
@dottedmag https://clojuredocs.org/clojure.walk/postwalk посмотри, там можно написать в update функции создание новых плюшек
@dottedmag есть еще одна функция встроенная обхода nested структур и применения функции на внутренних уровнях https://clojuredocs.org/clojure.walk/postwalk
да, /you winner
@larhat Вот я на specter посмотрел и не совсем понял. Как там ходить по фиксированному маршруту - это ясно, а вот по динамическому как-то сложно.
zipper
попробовал, но там есть такая засада: после создания зиппера из такой структуры данных, что у меня есть, теряется "ассоциативность" дерева — дети становятся упорядоченными. Так что стоя на узле, найти ребёнка по имени можно только сходив по всем детям слева направо.
я с чем-то могу путать, там есть какая-то фя, которая принимает node? и на основании этого дальше идет
ну вот да, все примеры - просто итерация. получается, нужно самому сбоку в процессе итерации заново пере-собирать дерево с модификациями
мы очень долго юзали instar (https://github.com/boxed/instar), там можно положить начальное дерево как seed для reduce’а и в reduce функции звать transform на нужных путях
(let [path ["a" "b" "c" "file"]
f (last path)
addr (reverse (cons :files (-> path count dec (repeat :dirs))))
path* (interleave addr path)]
(assoc-in {} path* f))
=> {:dirs {"a" {:dirs {"b" {:dirs {"c" {:files {"file" "file"}}}}}}}}
(defn pathify [path]
(let [xs (reverse (conj (repeat (dec (count path)) :dirs) :files))]
(interleave xs path)))
(let [path1 [:a :b :c :d]
path2 [:a :b :c]
path3 [:a :b :e :f]]
(-> {}
(assoc-in (pathify path1) (last path1))
(assoc-in (pathify path2) (last path2))
(assoc-in (pathify path3) (last path3))))
=>
{:dirs {:a {:dirs {:b {:dirs {:c {:files {:d :d}},
:e {:files {:f :f}}},
:files {:c :c}}}}}}
а вообще:
(defn assoc-in
"Associates a value in a nested associative structure, where ks is a
sequence of keys and v is the new value and returns a new nested structure.
If any levels do not exist, hash-maps will be created."
{:added "1.0"
:static true}
[m [k & ks] v]
(if ks
(assoc m k (assoc-in (get m k) ks v))
(assoc m k v)))
вместо (get m k)
можно написать (get m k (f))
, и передать f
, которая будет пустую дефолтную ноду возвращать