Thanks! One follow up question, though: will the first solution take O(n^2) time, or is clojure clever enough to keep track of where the end of a sequence is on its own (or, alternately, to start by concatenating the last two elements and working backward)? Or does it do some other cool magic to make this quick?
On Mar 1, 9:07 pm, Jason Wolfe <jawo...@berkeley.edu> wrote: > Hi, > > The problem is that you end up with the front of your worklist being > wrapped in <n-lines> nested calls to lazy-seq, one per each call to > concat. Then, realizing the first element causes a stack overflow. > This wouldn't happen if you reversed the arguments to concat, but then > you wouldn't get what you want. Some possibilities (untested): > > ; probably the shortest, most idiomatic solution? > > (defn getstrlist [file] > (apply concat > (take-while identity > (repeatedly #(getline file))))) > > ;or, using vectors, and written more like your solution: > > (defn getstrlist [file] > (loop [worklst []] > (if-let [x (getline file)] > (recur (into worklst x)) > worklst))) > > Cheers, > Jason > > On Mar 1, 4:53 pm, Zededarian <zededar...@gmail.com> wrote: > > > My ultimate goal is to get a list of all the words in a file in > > order. I have a function that will get a list of all the words on one > > line of this file in order, and I want to efficiently concatenate > > these lists to end up with one large list. I'm working with about > > 12000 lines right now, but in a perfect world I'd like to scale much > > higher. > > > I started off just using concat. Basically my code looks like: > > (defn getstrlist > > ([file] > > (loop [x (getline file) worklst '()] > > (if x > > (recur (getline file) (concat worklst (splitstr x))) > > worklst)))) > > > Then in the REPL, if I type (def a (getstrlist FILE)), it works fine. > > But if I try to output a or take (first a), I get a stack overflow > > error. I don't know why this is. I remember hearing somewhere that > > Clojure had lazy sequences, so my best guess is that it isn't actually > > concatenating anything, but is storing pointers to the start of all > > the lists on a stack that overflows when I try to evaluate one of > > these pointers. > > > I know in Scheme I would write this using metalists that keep track of > > the location of their last element: > > (define (concat metalst1 metalst2) > > (set-cdr! (car metalst1) (cdr metalst2)) > > (set-car! metalst1 (car metalst2)) > > metalst1) > > > (define (make-metalst lst) > > (cons (get-end lst) lst)) > > > (define (get-end lst) > > (if (null? lst) > > '() > > (if (null? (cdr lst)) > > lst > > (get-end (cdr lst))))) > > > Which would be fairly efficient. But since Clojure doesn't seem to > > have real lists, I'm not quite sure how I could port this over. I > > suppose I could implement my own cons pairs like an idiot and do all > > of this manually, but I figure I'm just not understanding the "Clojure > > solution" to this 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 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 -~----------~----~----~----~------~----~------~--~---