From: Jochen Schmidt on 12 Mar 2010 08:48 On 12 Mrz., 14:40, Jochen Schmidt <j...(a)crispylogics.com> wrote: > (defun group (list n) > (loop for e in list > for i upfrom 1 > collect e into group > if (zerop (mod i 5)) > collect (copy-list group) and do (setf group nil))) > Actually I missed the trailing incomplete group: (defun group (list n) (loop for e in list for i upfrom 1 collect e into group if (zerop (mod i 5)) collect (copy-list group) and do (setf group nil) finally when group collect group)) -- Jochen Schmidt CRISPYLOGICS Uhlandstr. 9, 90408 Nuremberg Fon +49 (0)911 517 999 82 Fax +49 (0)911 517 999 83 mailto:(format nil "~(~36r@~36r.~36r~)" 870180 1680085828711918828 16438) http://www.crispylogics.com
From: Jochen Schmidt on 12 Mar 2010 09:01 On 12 Mrz., 14:48, Jochen Schmidt <j...(a)crispylogics.com> wrote: > On 12 Mrz., 14:40, Jochen Schmidt <j...(a)crispylogics.com> wrote: > > > (defun group (list n) > > (loop for e in list > > for i upfrom 1 > > collect e into group > > if (zerop (mod i 5)) > > collect (copy-list group) and do (setf group nil))) > > Actually I missed the trailing incomplete group: > > (defun group (list n) > (loop for e in list > for i upfrom 1 > collect e into group > if (zerop (mod i 5)) > collect (copy-list group) and do (setf group nil) > finally when group collect group)) *sigh* I missed to replace the group-size n from my REPL example; AND this use of finally is actually not ANSI conform. One could rewrite it as: (defun group (list n) (check-type n (integer 1)) (loop for e in list for i upfrom 1 collect e into group if (zerop (mod i n)) collect (copy-list group) into result and do (setf group nil) finally return (if group (nconc result (list group)) result))) This doesn't make it look nicer though ;-) ciao, Jochen -- Jochen Schmidt CRISPYLOGICS Uhlandstr. 9, 90408 Nuremberg Fon +49 (0)911 517 999 82 Fax +49 (0)911 517 999 83 mailto:(format nil "~(~36r@~36r.~36r~)" 870180 1680085828711918828 16438) http://www.crispylogics.com
From: Rob Warnock on 12 Mar 2010 09:11 Jochen Schmidt <js(a)crispylogics.com> wrote: +--------------- | (defun group (list n) | (loop for e in list | for i upfrom 1 | collect e into group | if (zerop (mod i 5)) | collect (copy-list group) and do (setf group nil))) +--------------- Surely you meant (MOD I N), yes? In any case, even with the correction, the above doesn't work in CMUCL [might be a bug in CMUCL's "COLLECT...INTO..."]: > (group (iota 12) 3) ((0 1 2) (0 1 2 3 4 5) (0 1 2 3 4 5 6 7 8) (0 1 2 3 4 5 6 7 8 9 10 11)) > But this does: > (defun group (list n) (loop with group = nil for e in list and i upfrom 1 do (push e group) if (zerop (mod i n)) collect (reverse group) and do (setf group nil))) GROUP > (group (iota 12) 3) ((0 1 2) (3 4 5) (6 7 8) (9 10 11)) > (group (iota 12) 4) ((0 1 2 3) (4 5 6 7) (8 9 10 11)) > -Rob ----- Rob Warnock <rpw3(a)rpw3.org> 627 26th Avenue <URL:http://rpw3.org/> San Mateo, CA 94403 (650)572-2607
From: Jochen Schmidt on 12 Mar 2010 09:19 On 12 Mrz., 10:31, Tamas K Papp <tkp...(a)gmail.com> wrote: > Hi, > > I am trying to rewrite GROUP from On Lisp without recursion (just as an > exercise). My first attempt is below, I am wondering if there is a > nicer (more idiomatic, etc) way to do it. > > (defun group (list n) > "Return elements of LIST as a list of lists in groups of N." > (check-type n (integer 1)) > (let (sublist > result > (i 0)) > (dolist (element list) > (push element sublist) > (incf i) > (when (= i n) > (push (nreverse sublist) result) > (setf i 0 > sublist nil))) > (assert (zerop i) () "~A could not be broken up to sublists of ~A elements" list n) > (nreverse result))) > Here is an alternative to my other approach: (defun take-n (list n) (loop repeat n for e in list collect e)) (defun group (list n) (check-type n (integer 1)) (loop for tail = list then (nthcdr n tail) while tail collect (take-n tail n)))
From: Pillsy on 12 Mar 2010 09:29
On Mar 12, 4:31 am, Tamas K Papp <tkp...(a)gmail.com> wrote: > I am trying to rewrite GROUP from On Lisp without recursion (just as an > exercise). My first attempt is below, I am wondering if there is a > nicer (more idiomatic, etc) way to do it. I think REDUCE is a great function for problems like this. (defun group (list n) (check-type n (integer 1)) (let* ((i -1) (groups (reduce (lambda (e acc) (if (zerop (mod (incf i) n)) (cons (list e) acc) ;; You could also smash the car here to ;; reduce consing: (cons (cons e (car acc)) (cdr acc)))) list :from-end t :initial-value '()))) (if (/= (mod (1+ i) n) 0) (error "~A could not be broken up into sublists of ~A elements" list n) groups))) Cheers, Pillsy |