考慮向量嵌套在一個樹結構查找路徑中嵌套數據結構
(def tree [7 9 [7 5 3 [4 6 9] 9 3] 1 [2 7 9 9]])
我的目標是找到的路徑,可以通過找到的第一個偶數下面的數字中第一次出現遍歷樹:在上面的示例,這將是4,從根到該節點的路徑將是[2 3 0]
(def result [2 3 0])
我得到了一些困難寫壽存檔此功能。但是,下面的函數找到的第一個偶數,而不是它的路徑:
(defn find-even [x]
(if (vector? x)
(some #(when-let [subresult (find-even %)]
(when (even? subresult)
subresult)) x)
x))
(find-even tree) ;; 4
我將不得不爲了接收路徑的結果呢?
編輯
我想出了一個辦法做到這一點。這是一個功能,至少 - 工作:
(defn find-even-path [x]
(letfn [(traverse [x]
(if (vector? x)
(some (fn [[i v]] (when-let [subresult (traverse v)]
(when (even? (:value subresult))
(update subresult :path conj i))))
(map-indexed vector x))
{:path '()
:value x}))]
(when-let [result (traverse x)]
(vec (:path result)))))
(find-even-path tree) ;; [2 3 0]
但是,我仍然很好奇聽到什麼可以在這裏優化。它仍然看起來相當複雜,而且還不是尾遞歸。
太棒了!只有一件事:findt懶惰地搜索樹中的所有結果。爲了使你的測試公平,你應該包裝它(第一..) –
@AntonHarald謝謝!好點子。我只是修復它。令人驚訝的是,認識到懶惰矢量的第一個元素需要額外的300毫秒。 (可以通過在其最後一個參數中傳遞一個空列表而不是空向量來削減大約10-20毫秒,因爲'cons'在向量上速度很慢。) –
有趣。這怎麼解釋?唯一讓我想到的是:「Clojure中的許多惰性序列函數通過一次生成一個」N個元素的塊「來分解元素的實現」(http://insideclojure.org/2015/01/02/sequences /)這意味着懶惰的好處只會出現在大於N的'序列'上。如果我們的測試樹上的懶惰操作少於N,那麼必須對整個事件進行評估,然後調用結果中的「第一個」會導致額外的ms。但這只是猜測。 –