Clojure의 트리 데이터 구조에서 Spectre 사용
                                            
                                                
                                                
                                                
                                                
                                                
                                                 15166 단어  treeclojurescriptalgorithmsclojure
                    
자세히 살펴보면 마인드 매핑 구조가 트리 데이터 구조라는 것을 즉시 알 수 있습니다. 즉, 깊이 중첩된 구조를 처리해야 하고 작업에 적합한 도구가 필요합니다. 가장 먼저 떠오르는 것은 Specter 이라는 멋진 라이브러리입니다.
더 이상 고민하지 않고 몇 가지 코드를 확인하겠습니다. (프로젝트에서 제공한 코드 샘플)
CRUD 기능 중 하나는 id로 노드를 찾는 것이었습니다. 그래서 저는 이것을 생각해 냈습니다.
(require '[com.rpl.specter :as s])
(defn find-node-by-id [tree id]
  (s/select-first (s/walker #(= id (:id %))) tree))
Walker는 pred 함수가 진실 값을 반환하는 노드에 대해 깊이 우선 탐색을 실행합니다. pred가 참 값을 반환하면 Walker는 트리의 해당 분기 검색을 중지하고 나머지 데이터 구조 검색을 계속합니다.
모든 노드에는 고유한 id 속성이 있으므로
select-first 매크로를 사용하여 첫 번째 노드를 선택할 수 있습니다.또한 자식 ID로 부모 노드를 찾아야 했습니다.
(defn find-parent-by-child-id [tree child-id]
  (s/select-first
   (s/walker
    (fn [node]
      ((set (map :id (:children node))) child-id)))
   tree))
언젠가는 같은 수준의 노드를 찾아야 합니다.
(defn find-same-level-nodes [tree node-id]
  (let [parent (find-parent-by-child-id tree node-id)]
    (if (:root? parent)
      (:children parent)
      (->> parent
           :id
           (find-parent-by-child-id tree)
           :children
           (mapcat :children)))))
트리에서 일부 노드를 제거하고 업데이트해 보겠습니다. 그렇게 하기 전에 트리를 순회하기 위해
recursive-path를 정의할 수 있습니다. (또 다른 접근 방식)(def MAP-NODES
  (s/recursive-path [] p
    (s/cond-path
      sequential? (s/continue-then-stay s/ALL p)
      map? (s/continue-then-stay s/MAP-VALS p))))
Spectre는 순차적이거나 지도인 데이터를 발견하면 MAP-VALS에 대한 데이터 검색으로 재귀적으로 이동합니다. (우리는
coll? 만 사용할 수도 있습니다)자, 이 중요한 경로를 정의한 후 노드를 추가해 보겠습니다.
(defn add-node [tree parent-id node id]
  (let [node (assoc node :id id :h shape-h :w shape-w)
        tree (s/transform [q/MAP-NODES #(= parent-id (:id %)) :children]
                          #((fnil conj []) % node)
                          tree)]
    (update-positions tree parent-id id)))
add-node 는 MAP-NODES 를 사용하여 트리를 탐색하고 주어진 parent-id 를 찾으면 제공된 노드가 :children 에 추가됩니다.제거 작업;
(defn remove-node-by-id [tree id]
  (s/setval [MAP-NODES #(= id (:id %))] s/NONE tree))
여기에서는
setval 매크로를 사용하여 노드를 제거합니다.업데이트도 비슷합니다.
(defn update-node-by-id [tree id update-fn]
  (s/transform [MAP-NODES #(= id (:id %))] update-fn tree))
업데이트 기능 때문에
transform 대신 setval를 사용했습니다.중첩된 모든 자식을 부모 ID로 업데이트합시다. 먼저 모든 노드를 가져오는 함수를 만들어 보겠습니다.
(defn- traverse [node]
  (when (-> node :children seq)
    (lazy-cat (:children node) (map traverse (:children node)))))
(defn get-nodes [root]
  (->> root
       (traverse)
       (cons root)
       (flatten)
       (remove nil?)))
이제 모든 자식에게 업데이트 작업을 적용할 수 있습니다.
(defn update-children-by-parent-id [tree parent-id update-fn]
  (let [parent   (find-node-by-id tree parent-id)
        children (set (map :id (rest (get-nodes parent))))]
    (s/transform [MAP-NODES #(children (:id %))] update-fn tree)))
포스팅을 너무 길게 하고 싶지 않습니다. 나는 당신이 전체 그림을 가지고 있다고 생각합니다.
간단히 말해서 Spectre는 강력하고 재미있게 작업할 수 있습니다. 잘 구조화된 추상화로 상당히 복잡한 문제를 해결할 수 있습니다.
저와 비슷한 사용 사례가 있다면 적극 추천합니다.
Reference
이 문제에 관하여(Clojure의 트리 데이터 구조에서 Spectre 사용), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/ertugrulcetin/using-specter-on-tree-data-structures-in-clojure-2l15텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
                                
                                
                                
                                
                                
                                우수한 개발자 콘텐츠 발견에 전념
                                (Collection and Share based on the CC Protocol.)