2010/12/3 Ken Wesson <kwess...@gmail.com>

> On Fri, Dec 3, 2010 at 10:08 AM, Laurent PETIT <laurent.pe...@gmail.com>
> wrote:
> > 2010/12/3 Laurent PETIT <laurent.pe...@gmail.com>
> >> 2010/12/3 Anclj <anb...@gmail.com>
> >>> I've got:
> >>>
> >>> user> (split (slurp "data") #",")
> >>> ["0" "2" "1" "5" "2" "8" "3" "15" "4" "9"]
> >>>
> >>> And I would like:
> >>> {:0 2, :1 5, :2 8, :3 15, :4 9}
> >>>
> >>> Any idea?
> >>
> >>
> >> (let [s (split (slurp "data") #",")]
> >>   (zipmap (take-nth 2 s) (take-nth 2 (rest s))))
> >
> > Sorry, this respects the contract better:
> >
> > (let [s ["1" "2" "3" "4" "5" "6"]]
> >   (zipmap
> >     (map keyword (take-nth 2 s))
> >     (map #(Integer/valueOf %) (take-nth 2 (rest s)))))
>
> Both of these traverse s twice. How about:
>
> (let [s (split (slurp "data") #",")]
>   (into {}
>    (map (fn [[k v]] [(keyword (str k)) v])
>      (partition 2 s))))
>

Indeed, if I analyze my solution: the 2 take-nth traverse s 2 times
(creating 2 x 1/2 x n ISeq instances), and the two maps over the 2 resulting
seq traverse these resulting seqs also, creating again 2 x 1/2 x n ISeq
instances).
In the end, 2 x 1/2 x n + 2 x 1/2 x n = 2 x n ISeq instances are created and
visited.

Now yours :-) : (partition 2 s) traverses s once, and creates  1/2 n ISeq
instances each made of a seq of 2 ISeq instances => 1/2 n x 2 = n ISeq
instances.
Then map is applied and creates 1/2 x n vectors in 1/2 x n ISeq instances =>
also n instances created.
In the end, your solution also creates 2 x n instances (ISeq instances and
vector instances), before being consumed by into.

In fact, when one knows the algorithm needs to consume the entire seq *by
definition* (since in clojure datastructures themselves are not lazy, only
seqs are), it sometimes feels odd to create all these intermediate objects.

But I generally resist the temptation to too quickly resort to using loop,
which is the real solution to not create too many intermediate objects:

(let [s ["1" "2" "3" "4" "5" "6" "7" "8"]]
  (loop [s (seq s) m {}]
    (if s
      (recur (nnext s) (assoc m (keyword (first s)) (Integer/valueOf (fnext
s))))
      m)))

or else by leveraging transients:


(let [s ["1" "2" "3" "4" "5" "6" "7" "8"]]
  (loop [s (seq s) m (transient {})]
    (if s
      (recur (nnext s) (assoc! m (keyword (first s)) (Integer/valueOf (fnext
s))))
      (persistent! m))))

But really I generally not start (anymore) writing loops unless I see a
performance problem!

-- 
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