On Sun, Jun 13, 2010 at 8:39 AM, Oleg <oleg.richa...@gmail.com> wrote:
> Thank you, but could you provide me a little code snippet which will
> iterate through collection and assoc "children" key for each row.
>
> On 13 июн, 16:35, Andrzej <ndrwr...@googlemail.com> wrote:
>> On Sun, Jun 13, 2010 at 7:35 PM, Oleg <oleg.richa...@gmail.com> wrote:
>>
>> > Currently i'm just calling function, but there is a danger of
>> > StackOverflow. I can't use recur, because it's not last statement. As
>> > i can understand recur is good to build long sequences, but in my case
>> > i'm building hierarchy.
>>
>> Two potential solutions:
>> 1. Build a lazy hierarchy, i.e. instead of returning a nested
>> structure, return a function that produces it. It might be better to
>> use a built-in function tree-seq though (check the implementation of
>> file-seq and xml-seq).

I think a lazy hierarchy is the way to go, but tree-seq is a way
to walk a tree, not build one.

For a "real" example of a lazy hierarchy, you can look at
clojure.contrib.lazy-xml, which builds a lazy tree of XML nodes.
But it may be hard to learn from without getting lost in SAX API
craziness, so here's an attempt at a simpler example:

First, a function to return some children for a given parent:

        (defn children [parent]
          (vec (map + (repeat (* 10 parent)) (range 10))))

        (children 42)
        ;=> [420 421 422 423 424 425 426 427 428 429]

Note this is a vector and thus non-lazy, just as in your problem
description.

Now we want a function that returns a tree node for a given item.
For this example a node will be just a map with an :item and
a lazy sequence of :kids:

        (defn node [item]
          {:item item
           :kids (map node (children item))})

The fact that 'map' is lazy is critical here.  If we force that
map when creating a node, our first call to 'node' will force the
whole tree and could have unbounded recursion.  But 'map' is lazy
so we know that a single call to node will be O(1).  Only when we
actually realize the :kids seq will 'children' be called.

We can now build a tree and look something up in it:

        (-> (node 0) :kids (nth 3) :kids (nth 5) :kids (nth 8) :item)
        ;=> 358

So this is an infinitely deep tree that we can navigate without
any actual recursion, just as we can walk an infinite lazy seq
without recursion, and thus there's no threat that the stack will
overflow:

        (:item (reduce #(nth (:kids %1) %2)
                       (node 0)
                                   (take 5000 (cycle (range 10)))))
        ;=> 123456789012345678...67890123456789

Note that since these trees are infinitely deep, a depth-first
walk like tree-seq does is probably not very useful:

        (take 8 (map :item (tree-seq :kids :kids (node 1))))
        ;=> (1 10 100 1000 10000 100000 1000000 10000000)

Hope that helps!

--Chouser
http://joyofclojure.com/

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to