从树上迭代地构造Trie [英] Iteratively Construct Trie from a Tree

查看:164
本文介绍了从树上迭代地构造Trie的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

简介

以下函数迭代遍历由嵌套向量组成的树结构。它针对谓词测试每个叶子。通过该真值测试的所有叶子的路径将在 Trie结构中返回。后者以非冗余方式描述了所有找到的路径。

The following function iteratively traverses a tree structure made of nested vectors. It tests each leaf against a predicate. The paths to all leaves which pass that truth-test are returned in a Trie structure. The later describes all found paths in a non-redundant way.

(defn get-trie-of-matches [is? tree]
  (loop [[tree i path fk] [tree 0 [] nil]
         accum {}]
    (cond
      (>= i (count tree)) ;; end of level / go up
      (if (nil? fk) accum (recur fk accum))

      (vector? (tree i)) ;; level down
      (recur [(tree i) 0 (conj path i) [tree (inc i) path fk]] accum)

      (is? (tree i)) ;; match
      (let [new-accum (assoc-in accum (conj path i) {})]
        (recur [tree (inc i) path fk] new-accum))

      :else ;; next on same level
      (recur [tree (inc i) path fk] accum))))

有关进一步说明,请参阅这篇文章

For further explanations see this post.

示例

考虑以下树

(def tree [7 9 [7 5 3 [4 6 9] 9 3] 1 [2 7 9 9]])

应用于函数,使用甚至?作为谓词:

Applied to the function, using even? as a predicate:

(get-trie-of-matches even? tree)
=> {2 {3 {0 {}, 1 {}}}, 4 {0 {}}}

结果描述了中偶数的三条路径。即 2-3-0 2-3-1 4-0

The result describes the three paths to even numbers in tree. Namely 2-3-0, 2-3-1 and 4-0.

问题

即使以上功能有效,在遍历树时可能有更好的方法来构造Trie。目前,哈希映射被淹没了。通过assoc-in进行每场比赛。算法从一个级别到另一个级别相对遍历树结构,但是以全局方式将每个路径附加到 accum ,这不是必需的。此方法也是可行的,因为使用了散列映射。无论如何,为Trie使用顺序数据结构可能更好,以便于对其进行进一步的迭代。这不能用于上述方法。

Even though the above function works, there might be better ways to construct the Trie while traversing the tree. At the moment a hash-map is flooded. On each match via assoc-in. The algorithm traverses the tree structure relatively from level to level but attaches each path in a global fashion to accum, which is not necessary. Also this method is only possible since a hashmap is used. It might anyways be better to use a sequential data-structure for the Trie in order to facilitate further iterations over it. This could not be adopted to the above method.

问题

怎么可能在上述函数 get-trie-of-matches 中创建Trie而不依赖于特定于散列图的'全局''写'函数?

How could a Trie be created from within the above function get-trie-of-matches without relying on hash-map specific 'global' 'write' functions?

推荐答案

我建议看一下clojure的步行 api。

I would propose to take a look at clojure's walk api.

它允许您递归地将一些函数应用于嵌套集合。
在这种情况下,你可以使用 postwalk

It allows you to recursively apply some function to nested collections. In this case you could use postwalk:

user> (require '[clojure.walk :as w])
user> (w/postwalk-demo [1 3 [4 [6] 7] [[8]]])
Walked: 1
Walked: 3
Walked: 4
Walked: 6
Walked: [6]
Walked: 7
Walked: [4 [6] 7]
Walked: 8
Walked: [8]
Walked: [[8]]
Walked: [1 3 [4 [6] 7] [[8]]]

[1 3 [4 [6] 7] [[8]]]

关键是你可以在每一步替换任何项目:

The key thing is you can replace any item at every step:

user> (w/postwalk #(if (coll? %) (reverse %) (inc %))
                  [1 3 [4 [6] 7] [[8]]])

(((9)) (8 (7) 5) 4 2)

这里我们增加所有数字,并反转所有集合,保持嵌套结构。

Here we increment all the numbers, and reverse all the collections, keeping the nested structure.

现在适用于您的任务:
您可以遍历您的树,保持偶数的索引而不是空集合(例如包含偶数的集合,而不是空集合):

Now applying to your task: You could walk through your tree, keeping just even number's indices and not empty collections (e.g. collections containing even numbers, and not empty collections):

;; helper function
(defn empty-coll? [item]
  (and (coll? item) (not (seq item))))

(defn make-trie [pred tree]
  (w/postwalk
   #(if (coll? %)
      (keep-indexed (fn [idx item]
                      (cond (empty-coll? item) nil
                            (coll? item) (list idx item)
                            item idx
                            :else nil))
                    %)
      (pred %))
   tree))

in repl:

user> (def tree [7 9 [7 5 3 [4 6 9] 9 3] 1 [2 7 9 9]])
#'user/tree

user> (make-trie even? tree)
((2 ((3 (0 1)))) (4 (0)))

user> (make-trie #(> % 7) tree)
(1 (2 ((3 (2)) 4)) (4 (2 3)))

结构类似于您的地图。实际上,您可以通过对函数进行细微更改来生成所需的任何结构,例如您的地图结构:

The structure is similar to your map. In fact you can produce any structure you want with minor changes to the function, for example your map structure:

(defn make-trie-map [pred tree]
  (w/postwalk
   #(if (coll? %)
      (into {}
            (keep-indexed (fn [idx item]
                            (cond (empty-coll? item) nil
                                  (coll? item) {idx item}
                                  item {idx {}}
                                  :else nil))
                          %))
      (pred %))
   tree))

user> (make-trie-map even? tree)
{2 {3 {0 {}, 1 {}}}, 4 {0 {}}}

这篇关于从树上迭代地构造Trie的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆