Re: Why is my function faster with eval?
Very interesting thread! I'm having a similar problem and Michaels approach got me a small speedup (around 15%). When trying Mike's approach on my real data, if fails with IllegalArgumentException Too many arguments to struct constructor clojure. lang.PersistentStructMap.construct (PersistentStructMap.java:77) Op zondag 12 oktober 2014 03:51:46 UTC+2 schreef Mike Fikes: > > Hey Michael, > > Since your eval solution essentially "cookie-cutters" out maps, each with > the same keys, as fast as it can, I was playing around with what would > happen if you used records, and I cobbled together something that appears > to run twice as fast as the eval approach: > > (defn read-to-structs [rows] > (let [headers (->> > rows > first > (take-while (complement #{""})) > (map keyword)) > s (apply create-struct headers)] > (for [row (rest rows)] > (apply struct s row > > > Here are comparative timings: > > (time-fn read-to-maps) > "Elapsed time: 4871.02175 msecs" > => nil > (time-fn read-to-maps-partial) > "Elapsed time: 4814.730643 msecs" > => nil > (time-fn read-to-maps-fn) > "Elapsed time: 4815.230087 msecs" > => nil > (time-fn read-to-maps-eval) > "Elapsed time: 2466.048578 msecs" > => nil > (time-fn read-to-structs) > "Elapsed time: 1273.462618 msecs" > > I didn't test it too much, but it passed this: > > (= (read-to-maps csv-fix) (read-to-structs csv-fix)) > => true > > On Friday, October 10, 2014 4:21:01 PM UTC-4, Michael Blume wrote: >> >> https://github.com/MichaelBlume/eval-speed >> >> eval-speed.core=> (time-fn read-to-maps) >> "Elapsed time: 5551.011069 msecs" >> nil >> eval-speed.core=> (time-fn read-to-maps-fn) >> "Elapsed time: 5587.256991 msecs" >> nil >> eval-speed.core=> (time-fn read-to-maps-partial) >> "Elapsed time: 5606.649172 msecs" >> nil >> eval-speed.core=> (time-fn read-to-maps-eval) >> "Elapsed time: 2627.521592 msecs" >> nil >> >> Ben, I'd still like to understand exactly what work the CPU is doing in >> the uneval'd version that it's skipping in the eval'd version. It seems >> like in the generated bytecode there's going to be *some* concept of >> iterating through the row in either case, if only as part of the >> destructuring process. >> >> >> On Friday, October 10, 2014 1:07:08 PM UTC-7, Ben wrote: >>> >>> I believe it's because the `mapper` function is just creating and >>> returning a map literal. The "mapper" function in the evaled version is >>> something like this: >>> >>> user> (def names '[n1 n2 n3 n4]) >>> #'user/names >>> user> (def headers '[h1 h2 h3 h4]) >>> #'user/headers >>> user> `(fn [[~@names]] ~(zipmap headers names)) >>> (clojure.core/fn [[n1 n2 n3 n4]] {h4 n4, h3 n3, h2 n2, h1 n1}) ;; just >>> a map literal, whose keys are already known. >>> >>> Whereas in the first version, zipmap has to be called, iterating over >>> headers and names each time. >>> >>> On Fri, Oct 10, 2014 at 1:04 PM, Sean Corfield >>> wrote: >>> It may be more to do with the difference between `for` and `map`. How do these versions compare in your benchmark: (defn read-to-maps-partial [rows] (let [headers (->> rows first (take-while (complement #{""})) (map keyword))] (map (partial zipmap headers) (rest rows (defn read-to-maps-fn [rows] (let [headers (->> rows first (take-while (complement #{""})) (map keyword)) mapper (fn [row] (zipmap headers row))] (map mapper (rest rows Sean On Oct 10, 2014, at 11:42 AM, Michael Blume wrote: > So I'm reading a bunch of rows from a huge csv file and marshalling those rows into maps using the first row as keys. I wrote the function two ways: https://gist.github.com/MichaelBlume/c67d22df0ff9c225d956 and the version with eval is twice as fast and I'm kind of curious about why. Presumably the eval'd function still implicitly contains a list of keys, it's still implicitly treating each row as a seq and walking it, so I'm wondering what the seq-destructuring and the map literal are doing under the hood that's faster. >>> >>> >>> -- >>> Ben Wolfson >>> "Human kind has used its intelligence to vary the flavour of drinks, >>> which may be sweet, aromatic, fermented or spirit-based. ... Family and >>> social life also offer numerous other occasions to consume drinks for >>> pleasure." [Larousse, "Drink" entry] >>> >>> -- 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+un
Re: Why is my function faster with eval?
Hey Michael, Since your eval solution essentially "cookie-cutters" out maps, each with the same keys, as fast as it can, I was playing around with what would happen if you used records, and I cobbled together something that appears to run twice as fast as the eval approach: (defn read-to-structs [rows] (let [headers (->> rows first (take-while (complement #{""})) (map keyword)) s (apply create-struct headers)] (for [row (rest rows)] (apply struct s row Here are comparative timings: (time-fn read-to-maps) "Elapsed time: 4871.02175 msecs" => nil (time-fn read-to-maps-partial) "Elapsed time: 4814.730643 msecs" => nil (time-fn read-to-maps-fn) "Elapsed time: 4815.230087 msecs" => nil (time-fn read-to-maps-eval) "Elapsed time: 2466.048578 msecs" => nil (time-fn read-to-structs) "Elapsed time: 1273.462618 msecs" I didn't test it too much, but it passed this: (= (read-to-maps csv-fix) (read-to-structs csv-fix)) => true On Friday, October 10, 2014 4:21:01 PM UTC-4, Michael Blume wrote: > > https://github.com/MichaelBlume/eval-speed > > eval-speed.core=> (time-fn read-to-maps) > "Elapsed time: 5551.011069 msecs" > nil > eval-speed.core=> (time-fn read-to-maps-fn) > "Elapsed time: 5587.256991 msecs" > nil > eval-speed.core=> (time-fn read-to-maps-partial) > "Elapsed time: 5606.649172 msecs" > nil > eval-speed.core=> (time-fn read-to-maps-eval) > "Elapsed time: 2627.521592 msecs" > nil > > Ben, I'd still like to understand exactly what work the CPU is doing in > the uneval'd version that it's skipping in the eval'd version. It seems > like in the generated bytecode there's going to be *some* concept of > iterating through the row in either case, if only as part of the > destructuring process. > > > On Friday, October 10, 2014 1:07:08 PM UTC-7, Ben wrote: >> >> I believe it's because the `mapper` function is just creating and >> returning a map literal. The "mapper" function in the evaled version is >> something like this: >> >> user> (def names '[n1 n2 n3 n4]) >> #'user/names >> user> (def headers '[h1 h2 h3 h4]) >> #'user/headers >> user> `(fn [[~@names]] ~(zipmap headers names)) >> (clojure.core/fn [[n1 n2 n3 n4]] {h4 n4, h3 n3, h2 n2, h1 n1}) ;; just >> a map literal, whose keys are already known. >> >> Whereas in the first version, zipmap has to be called, iterating over >> headers and names each time. >> >> On Fri, Oct 10, 2014 at 1:04 PM, Sean Corfield >> wrote: >> >>> It may be more to do with the difference between `for` and `map`. How do >>> these versions compare in your benchmark: >>> >>> (defn read-to-maps-partial [rows] >>> (let [headers (->> >>> rows >>> first >>> (take-while (complement #{""})) >>> (map keyword))] >>> (map (partial zipmap headers) (rest rows >>> >>> (defn read-to-maps-fn [rows] >>> (let [headers (->> >>> rows >>> first >>> (take-while (complement #{""})) >>> (map keyword)) >>> mapper (fn [row] (zipmap headers row))] >>> (map mapper (rest rows >>> >>> Sean >>> >>> On Oct 10, 2014, at 11:42 AM, Michael Blume wrote: >>> > So I'm reading a bunch of rows from a huge csv file and marshalling >>> those rows into maps using the first row as keys. I wrote the function two >>> ways: https://gist.github.com/MichaelBlume/c67d22df0ff9c225d956 and the >>> version with eval is twice as fast and I'm kind of curious about why. >>> Presumably the eval'd function still implicitly contains a list of keys, >>> it's still implicitly treating each row as a seq and walking it, so I'm >>> wondering what the seq-destructuring and the map literal are doing under >>> the hood that's faster. >>> >>> >> >> >> -- >> Ben Wolfson >> "Human kind has used its intelligence to vary the flavour of drinks, >> which may be sweet, aromatic, fermented or spirit-based. ... Family and >> social life also offer numerous other occasions to consume drinks for >> pleasure." [Larousse, "Drink" entry] >> >> -- 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 --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: Why is my function faster with eval?
Zipmap doesn't use transients, so calling it at runtime will be significantly slower than constructing a literal map. http://dev.clojure.org/jira/browse/CLJ-1005 On Friday, October 10, 2014 11:42:14 AM UTC-7, Michael Blume wrote: > > So I'm reading a bunch of rows from a huge csv file and marshalling those > rows into maps using the first row as keys. I wrote the function two ways: > https://gist.github.com/MichaelBlume/c67d22df0ff9c225d956 and the version > with eval is twice as fast and I'm kind of curious about why. Presumably > the eval'd function still implicitly contains a list of keys, it's still > implicitly treating each row as a seq and walking it, so I'm wondering what > the seq-destructuring and the map literal are doing under the hood that's > faster. > -- 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 --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: Why is my function faster with eval?
On Oct 10, 2014, at 1:46 PM, Ben Wolfson wrote: > it's not quite at compile-time (since it's a dynamic call to eval, after all, > and "names" and "headers" aren't known at compile time), but it is calling it > eval-time, for lack of a better phrase. Yes, I meant when it compiles the code that eval executes at, er, run-time :) Sean > On Fri, Oct 10, 2014 at 1:35 PM, Sean Corfield wrote: > Ah, interesting... I hadn't considered it was running the zipmap at > compile-time so it only runs it once as opposed to running it for each row! > > Sean > > On Oct 10, 2014, at 1:06 PM, Ben Wolfson wrote: > > I believe it's because the `mapper` function is just creating and returning > > a map literal. The "mapper" function in the evaled version is something > > like this: > > > > user> (def names '[n1 n2 n3 n4]) > > #'user/names > > user> (def headers '[h1 h2 h3 h4]) > > #'user/headers > > user> `(fn [[~@names]] ~(zipmap headers names)) > > (clojure.core/fn [[n1 n2 n3 n4]] {h4 n4, h3 n3, h2 n2, h1 n1}) ;; just a > > map literal, whose keys are already known. > > > > Whereas in the first version, zipmap has to be called, iterating over > > headers and names each time. > signature.asc Description: Message signed with OpenPGP using GPGMail
Re: Why is my function faster with eval?
it's not quite at compile-time (since it's a dynamic call to eval, after all, and "names" and "headers" aren't known at compile time), but it is calling it eval-time, for lack of a better phrase. On Fri, Oct 10, 2014 at 1:35 PM, Sean Corfield wrote: > Ah, interesting... I hadn't considered it was running the zipmap at > compile-time so it only runs it once as opposed to running it for each row! > > Sean > > On Oct 10, 2014, at 1:06 PM, Ben Wolfson wrote: > > I believe it's because the `mapper` function is just creating and > returning a map literal. The "mapper" function in the evaled version is > something like this: > > > > user> (def names '[n1 n2 n3 n4]) > > #'user/names > > user> (def headers '[h1 h2 h3 h4]) > > #'user/headers > > user> `(fn [[~@names]] ~(zipmap headers names)) > > (clojure.core/fn [[n1 n2 n3 n4]] {h4 n4, h3 n3, h2 n2, h1 n1}) ;; just > a map literal, whose keys are already known. > > > > Whereas in the first version, zipmap has to be called, iterating over > headers and names each time. > > > -- Ben Wolfson "Human kind has used its intelligence to vary the flavour of drinks, which may be sweet, aromatic, fermented or spirit-based. ... Family and social life also offer numerous other occasions to consume drinks for pleasure." [Larousse, "Drink" entry] -- 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 --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: Why is my function faster with eval?
Ah, interesting... I hadn't considered it was running the zipmap at compile-time so it only runs it once as opposed to running it for each row! Sean On Oct 10, 2014, at 1:06 PM, Ben Wolfson wrote: > I believe it's because the `mapper` function is just creating and returning a > map literal. The "mapper" function in the evaled version is something like > this: > > user> (def names '[n1 n2 n3 n4]) > #'user/names > user> (def headers '[h1 h2 h3 h4]) > #'user/headers > user> `(fn [[~@names]] ~(zipmap headers names)) > (clojure.core/fn [[n1 n2 n3 n4]] {h4 n4, h3 n3, h2 n2, h1 n1}) ;; just a > map literal, whose keys are already known. > > Whereas in the first version, zipmap has to be called, iterating over headers > and names each time. signature.asc Description: Message signed with OpenPGP using GPGMail
Re: Why is my function faster with eval?
Did you run it enough times to fully warm up the JVM? On Fri, Oct 10, 2014 at 4:21 PM, Michael Blume wrote: > https://github.com/MichaelBlume/eval-speed > eval-speed.core=> (time-fn read-to-maps) > "Elapsed time: 5551.011069 msecs" > nil > eval-speed.core=> (time-fn read-to-maps-fn) > "Elapsed time: 5587.256991 msecs" > nil > eval-speed.core=> (time-fn read-to-maps-partial) > "Elapsed time: 5606.649172 msecs" > nil > eval-speed.core=> (time-fn read-to-maps-eval) > "Elapsed time: 2627.521592 msecs" > nil > Ben, I'd still like to understand exactly what work the CPU is doing in the > uneval'd version that it's skipping in the eval'd version. It seems like in > the generated bytecode there's going to be *some* concept of iterating > through the row in either case, if only as part of the destructuring > process. > On Friday, October 10, 2014 1:07:08 PM UTC-7, Ben wrote: >> >> I believe it's because the `mapper` function is just creating and >> returning a map literal. The "mapper" function in the evaled version is >> something like this: >> >> user> (def names '[n1 n2 n3 n4]) >> #'user/names >> user> (def headers '[h1 h2 h3 h4]) >> #'user/headers >> user> `(fn [[~@names]] ~(zipmap headers names)) >> (clojure.core/fn [[n1 n2 n3 n4]] {h4 n4, h3 n3, h2 n2, h1 n1}) ;; just a >> map literal, whose keys are already known. >> >> Whereas in the first version, zipmap has to be called, iterating over >> headers and names each time. >> >> On Fri, Oct 10, 2014 at 1:04 PM, Sean Corfield > > wrote: >> >>> It may be more to do with the difference between `for` and `map`. How do >>> these versions compare in your benchmark: >>> >>> (defn read-to-maps-partial [rows] >>> (let [headers (->> >>> rows >>> first >>> (take-while (complement #{""})) >>> (map keyword))] >>> (map (partial zipmap headers) (rest rows >>> >>> (defn read-to-maps-fn [rows] >>> (let [headers (->> >>> rows >>> first >>> (take-while (complement #{""})) >>> (map keyword)) >>> mapper (fn [row] (zipmap headers row))] >>> (map mapper (rest rows >>> >>> Sean >>> >>> On Oct 10, 2014, at 11:42 AM, Michael Blume >> > wrote: >>> > So I'm reading a bunch of rows from a huge csv file and marshalling >>> those rows into maps using the first row as keys. I wrote the function two >>> ways: https://gist.github.com/MichaelBlume/c67d22df0ff9c225d956 and the >>> version with eval is twice as fast and I'm kind of curious about why. >>> Presumably the eval'd function still implicitly contains a list of keys, >>> it's still implicitly treating each row as a seq and walking it, so I'm >>> wondering what the seq-destructuring and the map literal are doing under >>> the hood that's faster. >>> >>> >> >> >> -- >> Ben Wolfson >> "Human kind has used its intelligence to vary the flavour of drinks, which >> may be sweet, aromatic, fermented or spirit-based. ... Family and social >> life also offer numerous other occasions to consume drinks for pleasure." >> [Larousse, "Drink" entry] >> >> > -- > 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 > --- > You received this message because you are subscribed to the Google Groups > "Clojure" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to clojure+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/d/optout. -- 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 --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: Why is my function faster with eval?
https://github.com/MichaelBlume/eval-speed eval-speed.core=> (time-fn read-to-maps) "Elapsed time: 5551.011069 msecs" nil eval-speed.core=> (time-fn read-to-maps-fn) "Elapsed time: 5587.256991 msecs" nil eval-speed.core=> (time-fn read-to-maps-partial) "Elapsed time: 5606.649172 msecs" nil eval-speed.core=> (time-fn read-to-maps-eval) "Elapsed time: 2627.521592 msecs" nil Ben, I'd still like to understand exactly what work the CPU is doing in the uneval'd version that it's skipping in the eval'd version. It seems like in the generated bytecode there's going to be *some* concept of iterating through the row in either case, if only as part of the destructuring process. On Friday, October 10, 2014 1:07:08 PM UTC-7, Ben wrote: > > I believe it's because the `mapper` function is just creating and > returning a map literal. The "mapper" function in the evaled version is > something like this: > > user> (def names '[n1 n2 n3 n4]) > #'user/names > user> (def headers '[h1 h2 h3 h4]) > #'user/headers > user> `(fn [[~@names]] ~(zipmap headers names)) > (clojure.core/fn [[n1 n2 n3 n4]] {h4 n4, h3 n3, h2 n2, h1 n1}) ;; just a > map literal, whose keys are already known. > > Whereas in the first version, zipmap has to be called, iterating over > headers and names each time. > > On Fri, Oct 10, 2014 at 1:04 PM, Sean Corfield > wrote: > >> It may be more to do with the difference between `for` and `map`. How do >> these versions compare in your benchmark: >> >> (defn read-to-maps-partial [rows] >> (let [headers (->> >> rows >> first >> (take-while (complement #{""})) >> (map keyword))] >> (map (partial zipmap headers) (rest rows >> >> (defn read-to-maps-fn [rows] >> (let [headers (->> >> rows >> first >> (take-while (complement #{""})) >> (map keyword)) >> mapper (fn [row] (zipmap headers row))] >> (map mapper (rest rows >> >> Sean >> >> On Oct 10, 2014, at 11:42 AM, Michael Blume > > wrote: >> > So I'm reading a bunch of rows from a huge csv file and marshalling >> those rows into maps using the first row as keys. I wrote the function two >> ways: https://gist.github.com/MichaelBlume/c67d22df0ff9c225d956 and the >> version with eval is twice as fast and I'm kind of curious about why. >> Presumably the eval'd function still implicitly contains a list of keys, >> it's still implicitly treating each row as a seq and walking it, so I'm >> wondering what the seq-destructuring and the map literal are doing under >> the hood that's faster. >> >> > > > -- > Ben Wolfson > "Human kind has used its intelligence to vary the flavour of drinks, which > may be sweet, aromatic, fermented or spirit-based. ... Family and social > life also offer numerous other occasions to consume drinks for pleasure." > [Larousse, "Drink" entry] > > -- 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 --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: Why is my function faster with eval?
I believe it's because the `mapper` function is just creating and returning a map literal. The "mapper" function in the evaled version is something like this: user> (def names '[n1 n2 n3 n4]) #'user/names user> (def headers '[h1 h2 h3 h4]) #'user/headers user> `(fn [[~@names]] ~(zipmap headers names)) (clojure.core/fn [[n1 n2 n3 n4]] {h4 n4, h3 n3, h2 n2, h1 n1}) ;; just a map literal, whose keys are already known. Whereas in the first version, zipmap has to be called, iterating over headers and names each time. On Fri, Oct 10, 2014 at 1:04 PM, Sean Corfield wrote: > It may be more to do with the difference between `for` and `map`. How do > these versions compare in your benchmark: > > (defn read-to-maps-partial [rows] > (let [headers (->> > rows > first > (take-while (complement #{""})) > (map keyword))] > (map (partial zipmap headers) (rest rows > > (defn read-to-maps-fn [rows] > (let [headers (->> > rows > first > (take-while (complement #{""})) > (map keyword)) > mapper (fn [row] (zipmap headers row))] > (map mapper (rest rows > > Sean > > On Oct 10, 2014, at 11:42 AM, Michael Blume wrote: > > So I'm reading a bunch of rows from a huge csv file and marshalling > those rows into maps using the first row as keys. I wrote the function two > ways: https://gist.github.com/MichaelBlume/c67d22df0ff9c225d956 and the > version with eval is twice as fast and I'm kind of curious about why. > Presumably the eval'd function still implicitly contains a list of keys, > it's still implicitly treating each row as a seq and walking it, so I'm > wondering what the seq-destructuring and the map literal are doing under > the hood that's faster. > > -- Ben Wolfson "Human kind has used its intelligence to vary the flavour of drinks, which may be sweet, aromatic, fermented or spirit-based. ... Family and social life also offer numerous other occasions to consume drinks for pleasure." [Larousse, "Drink" entry] -- 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 --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: Why is my function faster with eval?
It may be more to do with the difference between `for` and `map`. How do these versions compare in your benchmark: (defn read-to-maps-partial [rows] (let [headers (->> rows first (take-while (complement #{""})) (map keyword))] (map (partial zipmap headers) (rest rows (defn read-to-maps-fn [rows] (let [headers (->> rows first (take-while (complement #{""})) (map keyword)) mapper (fn [row] (zipmap headers row))] (map mapper (rest rows Sean On Oct 10, 2014, at 11:42 AM, Michael Blume wrote: > So I'm reading a bunch of rows from a huge csv file and marshalling those > rows into maps using the first row as keys. I wrote the function two ways: > https://gist.github.com/MichaelBlume/c67d22df0ff9c225d956 and the version > with eval is twice as fast and I'm kind of curious about why. Presumably the > eval'd function still implicitly contains a list of keys, it's still > implicitly treating each row as a seq and walking it, so I'm wondering what > the seq-destructuring and the map literal are doing under the hood that's > faster. signature.asc Description: Message signed with OpenPGP using GPGMail
Re: Why is my function faster with eval?
Hello, Can you show the code you use for benchmarking? Le vendredi 10 octobre 2014, Michael Blume a écrit : > So I'm reading a bunch of rows from a huge csv file and marshalling those > rows into maps using the first row as keys. I wrote the function two ways: > https://gist.github.com/MichaelBlume/c67d22df0ff9c225d956 and the version > with eval is twice as fast and I'm kind of curious about why. Presumably > the eval'd function still implicitly contains a list of keys, it's still > implicitly treating each row as a seq and walking it, so I'm wondering what > the seq-destructuring and the map literal are doing under the hood that's > faster. > > -- > 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 > --- > You received this message because you are subscribed to the Google Groups > "Clojure" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to clojure+unsubscr...@googlegroups.com > . > For more options, visit https://groups.google.com/d/optout. > -- Laurent Petit -- 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 --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.