* How to delete all nil properties from a plist? @ 2015-08-01 22:03 Marcin Borkowski 2015-08-01 22:11 ` Marcin Borkowski [not found] ` <mailman.7749.1438467076.904.help-gnu-emacs@gnu.org> 0 siblings, 2 replies; 24+ messages in thread From: Marcin Borkowski @ 2015-08-01 22:03 UTC (permalink / raw) To: Help Gnu Emacs mailing list Hi all, so I'm still using plists, though I'm less and less sure that they are actually better than alists for my use-case. Now I need to delete all properties whose value is nil. I'm using this function: --8<---------------cut here---------------start------------->8--- (defun plist-clear (plist) "Return PLIST with all nil properties deleted." (cond ((< (length plist) 2) nil) ((null (cadr plist)) (cddr plist)) (t (cons (car plist) (cons (cadr plist) (plist-clear (cddr plist))))))) --8<---------------cut here---------------end--------------->8--- Question 1: is there a better way to write it? (Especially the last line.) Question 2: how would I do the analogous thing with alists? TIA, -- Marcin Borkowski http://octd.wmi.amu.edu.pl/en/Marcin_Borkowski Faculty of Mathematics and Computer Science Adam Mickiewicz University ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: How to delete all nil properties from a plist? 2015-08-01 22:03 How to delete all nil properties from a plist? Marcin Borkowski @ 2015-08-01 22:11 ` Marcin Borkowski 2015-08-02 1:32 ` Emanuel Berg [not found] ` <mailman.7753.1438479312.904.help-gnu-emacs@gnu.org> [not found] ` <mailman.7749.1438467076.904.help-gnu-emacs@gnu.org> 1 sibling, 2 replies; 24+ messages in thread From: Marcin Borkowski @ 2015-08-01 22:11 UTC (permalink / raw) To: Help Gnu Emacs mailing list On 2015-08-02, at 00:03, Marcin Borkowski <mbork@mbork.pl> wrote: > Hi all, > > so I'm still using plists, though I'm less and less sure that they are > actually better than alists for my use-case. Now I need to delete all > properties whose value is nil. I'm using this function: > > --8<---------------cut here---------------start------------->8--- > (defun plist-clear (plist) > "Return PLIST with all nil properties deleted." > (cond > ((< (length plist) 2) nil) > ((null (cadr plist)) (cddr plist)) > (t (cons (car plist) (cons (cadr plist) (plist-clear (cddr plist))))))) > --8<---------------cut here---------------end--------------->8--- > > Question 1: is there a better way to write it? (Especially the last > line.) > > Question 2: how would I do the analogous thing with alists? OK, so what about this? Is there a better way (which would probably mean, is such function already defined)? --8<---------------cut here---------------start------------->8--- (defun alist-clear (alist) "Return ALIST with all pairs with nil value deleted." (if alist (if (cdar alist) (cons (car alist) (alist-clear (cdr alist))) (alist-clear (cdr alist))))) --8<---------------cut here---------------end--------------->8--- TIA, -- Marcin Borkowski http://octd.wmi.amu.edu.pl/en/Marcin_Borkowski Faculty of Mathematics and Computer Science Adam Mickiewicz University ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: How to delete all nil properties from a plist? 2015-08-01 22:11 ` Marcin Borkowski @ 2015-08-02 1:32 ` Emanuel Berg [not found] ` <mailman.7753.1438479312.904.help-gnu-emacs@gnu.org> 1 sibling, 0 replies; 24+ messages in thread From: Emanuel Berg @ 2015-08-02 1:32 UTC (permalink / raw) To: help-gnu-emacs Marcin Borkowski <mbork@mbork.pl> writes: >> Hi all, so I'm still using plists, though I'm less >> and less sure that they are actually better than >> alists for my use-case. Now I need to delete all >> properties whose value is nil. I'm using this >> function: Try this: (require 'cl) (defun plist-drop-nil-props (l) (let((new) (prop nil) ) (cl-loop for x in l do (if (or (setq prop (not prop)) x) (setq new (append new (list x))) (setq new (butlast new)))) new)) (plist-drop-nil-props '(nil nil a 1 b 2 c nil d nil e 5 g nil nil nil) ) ; (a 1 b 2 e 5) -- underground experts united http://user.it.uu.se/~embe8573 ^ permalink raw reply [flat|nested] 24+ messages in thread
[parent not found: <mailman.7753.1438479312.904.help-gnu-emacs@gnu.org>]
* Re: How to delete all nil properties from a plist? [not found] ` <mailman.7753.1438479312.904.help-gnu-emacs@gnu.org> @ 2015-08-02 1:36 ` Pascal J. Bourguignon 2015-08-02 1:50 ` Emanuel Berg ` (2 more replies) 0 siblings, 3 replies; 24+ messages in thread From: Pascal J. Bourguignon @ 2015-08-02 1:36 UTC (permalink / raw) To: help-gnu-emacs Emanuel Berg <embe8573@student.uu.se> writes: > Marcin Borkowski <mbork@mbork.pl> writes: > >>> Hi all, so I'm still using plists, though I'm less >>> and less sure that they are actually better than >>> alists for my use-case. Now I need to delete all >>> properties whose value is nil. I'm using this >>> function: > > Try this: > > (require 'cl) > > (defun plist-drop-nil-props (l) > (let((new) > (prop nil) ) > (cl-loop for x in l > do (if (or (setq prop (not prop)) x) > (setq new (append new (list x))) > (setq new (butlast new)))) > new)) This is horrible. Again, you can't prevent yourself writing O(n²) code when O(n) would do perfectly. -- __Pascal Bourguignon__ http://www.informatimago.com/ “The factory of the future will have only two employees, a man and a dog. The man will be there to feed the dog. The dog will be there to keep the man from touching the equipment.” -- Carl Bass CEO Autodesk ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: How to delete all nil properties from a plist? 2015-08-02 1:36 ` Pascal J. Bourguignon @ 2015-08-02 1:50 ` Emanuel Berg 2015-08-02 3:55 ` Rusi [not found] ` <mailman.7754.1438480361.904.help-gnu-emacs@gnu.org> 2 siblings, 0 replies; 24+ messages in thread From: Emanuel Berg @ 2015-08-02 1:50 UTC (permalink / raw) To: help-gnu-emacs "Pascal J. Bourguignon" <pjb@informatimago.com> writes: > This is horrible. Again, you can't prevent yourself > writing O(n²) code when O(n) would do perfectly. Is it `append' or `butlast' that is linear as well? -- underground experts united http://user.it.uu.se/~embe8573 ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: How to delete all nil properties from a plist? 2015-08-02 1:36 ` Pascal J. Bourguignon 2015-08-02 1:50 ` Emanuel Berg @ 2015-08-02 3:55 ` Rusi 2015-08-02 16:21 ` Pascal J. Bourguignon [not found] ` <mailman.7754.1438480361.904.help-gnu-emacs@gnu.org> 2 siblings, 1 reply; 24+ messages in thread From: Rusi @ 2015-08-02 3:55 UTC (permalink / raw) To: help-gnu-emacs On Sunday, August 2, 2015 at 7:06:24 AM UTC+5:30, Pascal J. Bourguignon wrote: > Emanuel Berg writes: > > > Marcin Borkowski writes: > > > >>> Hi all, so I'm still using plists, though I'm less > >>> and less sure that they are actually better than > >>> alists for my use-case. Now I need to delete all > >>> properties whose value is nil. I'm using this > >>> function: > > > > Try this: > > > > (require 'cl) > > > > (defun plist-drop-nil-props (l) > > (let((new) > > (prop nil) ) > > (cl-loop for x in l > > do (if (or (setq prop (not prop)) x) > > (setq new (append new (list x))) > > (setq new (butlast new)))) > > new)) > > This is horrible. Again, you can't prevent yourself writing O(n²) code > when O(n) would do perfectly. Hey Pascal! If O(n²) is 'horrible' what is O(n³)? And O(n⁴) ? And the stuff in NP? [I suppose the french lexicon has many adjectives...] BTW: Thanks for being civilized/cultured and using a non-ASCII character ² when it is appropriate. Vive la Unicode! ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: How to delete all nil properties from a plist? 2015-08-02 3:55 ` Rusi @ 2015-08-02 16:21 ` Pascal J. Bourguignon 0 siblings, 0 replies; 24+ messages in thread From: Pascal J. Bourguignon @ 2015-08-02 16:21 UTC (permalink / raw) To: help-gnu-emacs Rusi <rustompmody@gmail.com> writes: > On Sunday, August 2, 2015 at 7:06:24 AM UTC+5:30, Pascal J. Bourguignon wrote: >> Emanuel Berg writes: >> >> > Marcin Borkowski writes: >> > >> >>> Hi all, so I'm still using plists, though I'm less >> >>> and less sure that they are actually better than >> >>> alists for my use-case. Now I need to delete all >> >>> properties whose value is nil. I'm using this >> >>> function: >> > >> > Try this: >> > >> > (require 'cl) >> > >> > (defun plist-drop-nil-props (l) >> > (let((new) >> > (prop nil) ) >> > (cl-loop for x in l >> > do (if (or (setq prop (not prop)) x) >> > (setq new (append new (list x))) >> > (setq new (butlast new)))) >> > new)) >> >> This is horrible. Again, you can't prevent yourself writing O(n²) code >> when O(n) would do perfectly. > > Hey Pascal! > If O(n²) is 'horrible' what is O(n³)? And O(n⁴) ? > And the stuff in NP? > [I suppose the french lexicon has many adjectives...] What's horrible is the ratio between the actual O(.) over the possible O(.). > BTW: Thanks for being civilized/cultured and using a non-ASCII character ² > when it is appropriate. Vive la Unicode! -- __Pascal Bourguignon__ http://www.informatimago.com/ “The factory of the future will have only two employees, a man and a dog. The man will be there to feed the dog. The dog will be there to keep the man from touching the equipment.” -- Carl Bass CEO Autodesk ^ permalink raw reply [flat|nested] 24+ messages in thread
[parent not found: <mailman.7754.1438480361.904.help-gnu-emacs@gnu.org>]
* Re: How to delete all nil properties from a plist? [not found] ` <mailman.7754.1438480361.904.help-gnu-emacs@gnu.org> @ 2015-08-02 16:24 ` Pascal J. Bourguignon 2015-08-05 23:08 ` Emanuel Berg [not found] ` <mailman.7864.1438816202.904.help-gnu-emacs@gnu.org> 0 siblings, 2 replies; 24+ messages in thread From: Pascal J. Bourguignon @ 2015-08-02 16:24 UTC (permalink / raw) To: help-gnu-emacs Emanuel Berg <embe8573@student.uu.se> writes: > "Pascal J. Bourguignon" <pjb@informatimago.com> > writes: > >> This is horrible. Again, you can't prevent yourself >> writing O(n²) code when O(n) would do perfectly. > > Is it `append' or `butlast' that is linear as well? Both. -- __Pascal Bourguignon__ http://www.informatimago.com/ “The factory of the future will have only two employees, a man and a dog. The man will be there to feed the dog. The dog will be there to keep the man from touching the equipment.” -- Carl Bass CEO Autodesk ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: How to delete all nil properties from a plist? 2015-08-02 16:24 ` Pascal J. Bourguignon @ 2015-08-05 23:08 ` Emanuel Berg [not found] ` <mailman.7864.1438816202.904.help-gnu-emacs@gnu.org> 1 sibling, 0 replies; 24+ messages in thread From: Emanuel Berg @ 2015-08-05 23:08 UTC (permalink / raw) To: help-gnu-emacs "Pascal J. Bourguignon" <pjb@informatimago.com> writes: >>> This is horrible. Again, you can't prevent >>> yourself writing O(n²) code when O(n) would >>> do perfectly. >> >> Is it `append' or `butlast' that is linear as well? > > Both. OK! It would be useful to have a list with the time complexities of all the list operators. Because here (with `append' and `butlast') it isn't clear from what those functions do that they are linear. On the contrary: if we think of an open bike chain in a workshop, then to put another link at either end isn't linear, it is O(1), as is removing a link from either end. So I think my algorithm is actually linear (but not the implementation you saw) if only I replaced those functions with manually re-linking the items (because if the list is built manually, the last item could be stored, and then linked further to in constant time which would imply appending to the list as that item is already part of the list, the last part) - I don't know how to do that right now, perhaps I'll be back if I don't find something else to do... -- underground experts united http://user.it.uu.se/~embe8573 ^ permalink raw reply [flat|nested] 24+ messages in thread
[parent not found: <mailman.7864.1438816202.904.help-gnu-emacs@gnu.org>]
* Re: How to delete all nil properties from a plist? [not found] ` <mailman.7864.1438816202.904.help-gnu-emacs@gnu.org> @ 2015-08-05 23:30 ` Pascal J. Bourguignon 2015-08-05 23:49 ` Emanuel Berg ` (3 more replies) 0 siblings, 4 replies; 24+ messages in thread From: Pascal J. Bourguignon @ 2015-08-05 23:30 UTC (permalink / raw) To: help-gnu-emacs Emanuel Berg <embe8573@student.uu.se> writes: > "Pascal J. Bourguignon" <pjb@informatimago.com> > writes: > >>>> This is horrible. Again, you can't prevent >>>> yourself writing O(n²) code when O(n) would >>>> do perfectly. >>> >>> Is it `append' or `butlast' that is linear as well? >> >> Both. > > OK! > > It would be useful to have a list with the time > complexities of all the list operators. Because here > (with `append' and `butlast') it isn't clear from what > those functions do that they are linear. On the > contrary: if we think of an open bike chain in > a workshop, then to put another link at either end > isn't linear, it is O(1), as is removing a link from > either end. Depends on what end of the chain you hold. To make it easier, imagine this bike chain, but 10 km long, obviously, you have one end in hand, and the other is stored three workshop beyond. To find this other end, you have to go thru each link. O(n). There is no such list of complexities because: 1- it is obvious. When you've studied lisp, you have implemented most of them. 2- in most cases, the algorithms are not specified, so an implementation would be free to provide something more efficient, if it was possible. 3- there is some expectations on the part of CL users, and sometimes an implementation may use a worse algorithm. Then its users will complain and a better algorithm is implemented. So mostly all implementations have similar time and space complexities. Nonetheless, if you find it would be useful to have such a list, you can establish it. There are 636 functions in CL. If you research the best algorithms for each, noting the time and space complexities, and finding what complexities and (approximate) actual factors each implementation provide, for 2 functions each day, you will be done in less than a year. > So I think my algorithm is actually linear (but not > the implementation you saw) if only I replaced those > functions with manually re-linking the items (because > if the list is built manually, the last item could be > stored, and then linked further to in constant time > which would imply appending to the list as that item > is already part of the list, the last part) - I don't > know how to do that right now, perhaps I'll be back if > I don't find something else to do... Absolutely. Also, notice that doing that, or consing onto the beginning of the list and calling nreverse when you're done are equivalent time-complexity wise. There may be some difference re: cache in actual contemporaneous computers but it can be seen only on very long lists. -- __Pascal Bourguignon__ http://www.informatimago.com/ “The factory of the future will have only two employees, a man and a dog. The man will be there to feed the dog. The dog will be there to keep the man from touching the equipment.” -- Carl Bass CEO Autodesk ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: How to delete all nil properties from a plist? 2015-08-05 23:30 ` Pascal J. Bourguignon @ 2015-08-05 23:49 ` Emanuel Berg 2015-08-06 0:30 ` Emanuel Berg ` (2 subsequent siblings) 3 siblings, 0 replies; 24+ messages in thread From: Emanuel Berg @ 2015-08-05 23:49 UTC (permalink / raw) To: help-gnu-emacs "Pascal J. Bourguignon" <pjb@informatimago.com> writes: > Nonetheless, if you find it would be useful to have > such a list, you can establish it. > > There are 636 functions in CL. > > If you research the best algorithms for each, noting > the time and space complexities, and finding what > complexities and (approximate) actual factors each > implementation provide, for 2 functions each day, > you will be done in less than a year. You don't have to have a list of every single function, the most common will do - but of course, the more complete the list, the better... But how do you find out? Before you told me, I didn't know `append' was linear. Do you examine the code and do analysis? If so, I'll pass this project :) -- underground experts united http://user.it.uu.se/~embe8573 ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: How to delete all nil properties from a plist? 2015-08-05 23:30 ` Pascal J. Bourguignon 2015-08-05 23:49 ` Emanuel Berg @ 2015-08-06 0:30 ` Emanuel Berg 2015-08-06 1:05 ` John Mastro [not found] ` <mailman.7867.1438818687.904.help-gnu-emacs@gnu.org> [not found] ` <mailman.7869.1438821124.904.help-gnu-emacs@gnu.org> 3 siblings, 1 reply; 24+ messages in thread From: Emanuel Berg @ 2015-08-06 0:30 UTC (permalink / raw) To: help-gnu-emacs "Pascal J. Bourguignon" <pjb@informatimago.com> writes: > Also, notice that doing that, or consing onto the > beginning of the list and calling nreverse when > you're done are equivalent time-complexity wise. > There may be some difference re: cache in actual > contemporaneous computers but it can be seen only on > very long lists. This only uses `cons', `cdr', and `nreverse', so it is linear, right? ("linear" only from going thru the input list.) (require 'cl) (defun plist-drop-nil-props (l) (let ((new) (nil-prop) (prop) ) (cl-loop for x in l do (if (setq prop (not prop)) (if x (setq new (cons x new)) (setq nil-prop t)) (if x (if nil-prop (setq nil-prop nil) (setq new (cons x new)) ) (setq new (cdr new) )))) (nreverse new) )) ;; (plist-drop-nil-props '(nil 1 a 1 b 2 c nil d nil e 5 g nil h) ) ;; => (a 1 b 2 e 5 h) So the list so far: linear: butlast, append constant: cons, cdr, nreverse But the OP should probably use yours anyway... :) -- underground experts united http://user.it.uu.se/~embe8573 ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: How to delete all nil properties from a plist? 2015-08-06 0:30 ` Emanuel Berg @ 2015-08-06 1:05 ` John Mastro 2015-08-06 1:07 ` John Mastro 0 siblings, 1 reply; 24+ messages in thread From: John Mastro @ 2015-08-06 1:05 UTC (permalink / raw) To: help-gnu-emacs@gnu.org > This only uses `cons', `cdr', and `nreverse', so it is > linear, right? ("linear" only from going thru the > input list.) > > (require 'cl) > > (defun plist-drop-nil-props (l) > (let ((new) > (nil-prop) > (prop) ) > (cl-loop for x in l > do (if (setq prop (not prop)) > (if x (setq new (cons x new)) > (setq nil-prop t)) > (if x > (if nil-prop (setq nil-prop nil) > (setq new (cons x new)) ) > (setq new (cdr new) )))) > (nreverse new) )) I took a swing at this too for the fun of it. Here's what I ended up with: (defun plist-drop-nil-props (plist) (let* ((result (list 'head)) (last result)) (cl-loop for (key val) on plist by #'cddr do (when-let (new (and val (list key val))) (setcdr last new) (setq last (cdr new)))) (cdr result))) The `when-let' macro is new in Emacs 25 but obviously it can be trivially replaced with `let' and `when' (or `-when-let' from dash.el). -- john ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: How to delete all nil properties from a plist? 2015-08-06 1:05 ` John Mastro @ 2015-08-06 1:07 ` John Mastro 0 siblings, 0 replies; 24+ messages in thread From: John Mastro @ 2015-08-06 1:07 UTC (permalink / raw) To: help-gnu-emacs@gnu.org > (defun plist-drop-nil-props (plist) > (let* ((result (list 'head)) > (last result)) > (cl-loop for (key val) on plist by #'cddr do > (when-let (new (and val (list key val))) > (setcdr last new) > (setq last (cdr new)))) > (cdr result))) Or the same thing with `while' in place of `cl-loop': (defun drop-nil-props (plist) (let* ((result (list 'head)) (last result)) (while plist (let* ((key (pop plist)) (val (pop plist)) (new (and val (list key val)))) (when new (setcdr last new) (setq last (cdr new))))) (cdr result))) -- john ^ permalink raw reply [flat|nested] 24+ messages in thread
[parent not found: <mailman.7867.1438818687.904.help-gnu-emacs@gnu.org>]
* Re: How to delete all nil properties from a plist? [not found] ` <mailman.7867.1438818687.904.help-gnu-emacs@gnu.org> @ 2015-08-06 2:32 ` Pascal J. Bourguignon 2015-08-07 22:21 ` Emanuel Berg 0 siblings, 1 reply; 24+ messages in thread From: Pascal J. Bourguignon @ 2015-08-06 2:32 UTC (permalink / raw) To: help-gnu-emacs Emanuel Berg <embe8573@student.uu.se> writes: > "Pascal J. Bourguignon" <pjb@informatimago.com> > writes: > >> Nonetheless, if you find it would be useful to have >> such a list, you can establish it. >> >> There are 636 functions in CL. >> >> If you research the best algorithms for each, noting >> the time and space complexities, and finding what >> complexities and (approximate) actual factors each >> implementation provide, for 2 functions each day, >> you will be done in less than a year. > > You don't have to have a list of every single > function, the most common will do - but of course, the > more complete the list, the better... > > But how do you find out? Before you told me, I didn't > know `append' was linear. Do you examine the code and > do analysis? If so, I'll pass this project :) Why would you pass, reading the source of an implementation is one of the most instructive things you can do as a programmer. Indeed, reading the sources of APPEND, and even, comparing it across several implementation would let you learn a lot. The alternative course, is not to read an implementation, but to write an implementation yourself! You read the clhs: append &rest lists => result Arguments and Values: list---each must be a proper list except the last, which may be any object. result---an object. This will be a list unless the last list was not a list and all preceding lists were null. Description: append returns a new list that is the concatenation of the copies. lists are left unchanged; the list structure of each of lists except the last is copied. The last argument is not copied; it becomes the cdr of the final dotted pair of the concatenation of the preceding lists, or is returned directly if there are no preceding non-empty lists. and you implement it. So, let's see, the last list must not be copied, but taken as is for the result. Then we must copy the other lists, and concatenate them. So: (shadow 'append) (defun append (&rest lists) (when lists (let* ((lists (reverse lists)) (result (pop lists))) (dolist (list lists result) (setf result (nconc (copy-list list) result)))))) This is clearly O(n), with n = (reduce 'length (butlast lists)), since we call copy-list on all lists but the last, copy-list is O(length(list)), and nconc which is also O(length(list)) so our function is O(Σ(2*length(list))), summing over all the lists but the last one, = O(reduce 'length (butlast lists)) But if you implement it yourself, 1- you won't learn the same, 2- you'll always have a doubt whether you've found the most efficient algorithm, (unless you can prove no algorithm can be more efficient than yours), 3- you might make an error, 4- you won't learn the various implementation techniques used in the implementations. Come on, it's not hard, just type M-. and eg. on ccl you get: (defun append (&rest lists) (declare (dynamic-extent lists)) "Construct a new list by concatenating the list arguments" (if lists (let* ((head (cons nil nil)) (tail head)) (declare (dynamic-extent head) (cons head tail)) (do* () ((null lists) (cdr head)) (let* ((list (pop lists))) (if (null lists) (rplacd tail list) (dolist (element list) (setq tail (cdr (rplacd tail (cons element nil))))))))))) and on sbcl you get: (defun append (&rest lists) #!+sb-doc "Construct a new list by concatenating the list arguments" (declare (truly-dynamic-extent lists) (optimize speed)) (labels ((fail (object) (error 'type-error :datum object :expected-type 'list)) (append-into (last-cons current rest) ;; Set (CDR LAST-CONS) to (APPLY #'APPEND CURRENT REST). (declare (cons last-cons rest)) (if (listp current) (if (consp current) ;; normal case, cdr down the list (append-into (setf (cdr last-cons) (list (car current))) (cdr current) rest) ;; empty list (let ((more (cdr rest))) (if (null more) (setf (cdr last-cons) (car rest)) (append-into last-cons (car rest) more)))) (fail current))) (append1 (lists) (let ((current (car lists)) (rest (cdr lists))) (cond ((null rest) current) ((consp current) (let ((result (truly-the cons (list (car current))))) (append-into result (cdr current) rest) result)) ((null current) (append1 rest)) (t (fail current)))))) (append1 lists))) and also, you get a compiler-macros for append, which you should have a look at, since it actually use a different function in some cases. and for clisp you get: LISPFUN(append,seclass_read,0,0,rest,nokey,0,NIL) { /* (APPEND {list}), CLTL p. 268 */ if (argcount==0) { VALUES1(NIL); /* no arguments -> return NIL as result */ } else { /* Append arguments. Run the loop argcount-1 times: */ while (--argcount) { /* STACK_0 = result list from right. */ /* STACK_1 := (append STACK_1 STACK_0), increase STACK by 1: */ var object list1; { var object list2 = popSTACK(); /* result list (from right) */ list1 = STACK_0; /* Argument to be added to the front */ STACK_0 = list2; /* stack resulting list */ } /* list1 needs to be a list: */ if (atomp(list1)) if (nullp(list1)) ; /* if list1=NIL: (append nil x) = x, do nothing */ else error_list(list1); else { /* (append list1 STACK_0), and list1 is a Cons: */ /* Copy list1 and keep last Cons: */ var object run; pushSTACK(list1); { var object new_list = allocate_cons(); run = STACK_0; /* run runs through the old list list1 */ Car(new_list) = Car(run); STACK_0 = new_list; pushSTACK(new_list); } /* Loop: STACK_1 has the full copy, STACK_0 = LAST of it, */ /* run = the corresponding Cons of the original list list1. */ while ( run=Cdr(run), !endp(run) ) { /* one more Cons */ pushSTACK(run); /* save run */ var object new_cons = allocate_cons(); /* allocate new Cons */ run = popSTACK(); /* put back run */ Cdr(STACK_0) = new_cons; /* and add as CDR of the LAST */ Car(new_cons) = Car(run); /* copy CAR */ STACK_0 = new_cons; /* this is now the new LAST */ } /* Copy ready. STACK_2 = current result list, */ /* STACK_1 = copy of list1, STACK_0 = LAST of it. */ run = popSTACK(); /* end of copy */ list1 = popSTACK(); /* copy finished */ /*if (!nullp(Cdr(run))) ???? error_proper_list_dotted(TheSubr(subr_self)->name,Cdr(run));*/ Cdr(run) = STACK_0; /* add result copy */ STACK_0 = list1; /* and the is the new result list */ } } VALUES1(popSTACK()); /* result list as value */ } } and in ecl: static cl_object * append_into(cl_object head, cl_object *tail, cl_object l) { if (!Null(*tail)) { /* (APPEND '(1 . 2) 3) */ FEtype_error_proper_list(head); } while (CONSP(l)) { cl_object cons = ecl_list1(ECL_CONS_CAR(l)); *tail = cons; tail = &ECL_CONS_CDR(cons); l = ECL_CONS_CDR(l); } *tail = l; return tail; } @(defun append (&rest rest) cl_object head = ECL_NIL, *tail = &head; @ for (; narg > 1; narg--) { cl_object other = ecl_va_arg(rest); tail = append_into(head, tail, other); } if (narg) { if (!Null(*tail)) { /* (APPEND '(1 . 2) 3) */ FEtype_error_proper_list(head); } *tail = ecl_va_arg(rest); } @(return head) @) -- __Pascal Bourguignon__ http://www.informatimago.com/ “The factory of the future will have only two employees, a man and a dog. The man will be there to feed the dog. The dog will be there to keep the man from touching the equipment.” -- Carl Bass CEO Autodesk ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: How to delete all nil properties from a plist? 2015-08-06 2:32 ` Pascal J. Bourguignon @ 2015-08-07 22:21 ` Emanuel Berg 0 siblings, 0 replies; 24+ messages in thread From: Emanuel Berg @ 2015-08-07 22:21 UTC (permalink / raw) To: help-gnu-emacs "Pascal J. Bourguignon" <pjb@informatimago.com> writes: > Why would you pass, reading the source of an > implementation is one of the most instructive things > you can do as a programmer. > > Indeed, reading the sources of APPEND, and even, > comparing it across several implementation would let > you learn a lot. > > The alternative course, is not to read an > implementation, but to write an > implementation yourself! In principle I don't disagree with either claim (that reading code and re-implementing basic algorithms and data structures is educational). But at this point that kind of sparring doesn't fry my diodes. I only want to solve real problems that has to do with real systems. The small exception I make is when people ask on this list. Sometimes that makes me do stuff I normally wouldn't. It is a pleasant game. -- underground experts united http://user.it.uu.se/~embe8573 ^ permalink raw reply [flat|nested] 24+ messages in thread
[parent not found: <mailman.7869.1438821124.904.help-gnu-emacs@gnu.org>]
* Re: How to delete all nil properties from a plist? [not found] ` <mailman.7869.1438821124.904.help-gnu-emacs@gnu.org> @ 2015-08-06 2:40 ` Pascal J. Bourguignon 2015-08-07 22:32 ` Emanuel Berg [not found] ` <mailman.7963.1438986782.904.help-gnu-emacs@gnu.org> 0 siblings, 2 replies; 24+ messages in thread From: Pascal J. Bourguignon @ 2015-08-06 2:40 UTC (permalink / raw) To: help-gnu-emacs Emanuel Berg <embe8573@student.uu.se> writes: > "Pascal J. Bourguignon" <pjb@informatimago.com> > writes: > >> Also, notice that doing that, or consing onto the >> beginning of the list and calling nreverse when >> you're done are equivalent time-complexity wise. >> There may be some difference re: cache in actual >> contemporaneous computers but it can be seen only on >> very long lists. > > This only uses `cons', `cdr', and `nreverse', so it is > linear, right? ("linear" only from going thru the > input list.) Being O(n) doesn't come automatically by using only cons cdr and nreverse. It depends on the structure of the algorithm! http://discrete.gr/complexity/ > (require 'cl) > > (defun plist-drop-nil-props (l) > (let ((new) > (nil-prop) > (prop) ) > (cl-loop for x in l Here you are doing the loop body once for each element in the list l. Therefore you will be repeating the loop body (length l) times. The complexity of your algorithm will therefore be: O( (* (length l) (complexity-of loop-body) ) > do (if (setq prop (not prop)) > (if x (setq new (cons x new)) > (setq nil-prop t)) NEVER put the then on the same line as the test! > (if x > (if nil-prop (setq nil-prop nil) > (setq new (cons x new)) ) > (setq new (cdr new) )))) Fortunately, your loop body contains a fixed number of instruction, that doesn't depend on the length of the list or on any other value that depend on the length of the list. Therefore it is O(1) and O( (* (length l) O(1)) ) = O(length l) > (nreverse new) )) (length new) is also bound by (length l), so the complexity of (nreverse new) is O(length l). O(length l) + O(length l) = O(length l). > constant: cons, cdr, nreverse No. your call to nreverse is O(length l). -- __Pascal Bourguignon__ http://www.informatimago.com/ “The factory of the future will have only two employees, a man and a dog. The man will be there to feed the dog. The dog will be there to keep the man from touching the equipment.” -- Carl Bass CEO Autodesk ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: How to delete all nil properties from a plist? 2015-08-06 2:40 ` Pascal J. Bourguignon @ 2015-08-07 22:32 ` Emanuel Berg [not found] ` <mailman.7963.1438986782.904.help-gnu-emacs@gnu.org> 1 sibling, 0 replies; 24+ messages in thread From: Emanuel Berg @ 2015-08-07 22:32 UTC (permalink / raw) To: help-gnu-emacs "Pascal J. Bourguignon" <pjb@informatimago.com> writes: > Being O(n) doesn't come automatically by using only > cons cdr and nreverse. It depends on the structure > of the algorithm! http://discrete.gr/complexity/ Yes, of course. But doesn't it come automatically if the list is iterated and there is only constant functions in the loop body? The only thing that is linear is the iteration of the list. If on the other hand the body contains something that is linear as well, as was the case with `append' and `butlast', then it'll be linear*linear - i.e. quadratic or O(n^2). > NEVER put the then on the same line as the test! ... why? > Fortunately, your loop body contains a fixed number > of instruction, that doesn't depend on the length of > the list or on any other value that depend on the > length of the list. Therefore it is O(1) and O( (* > (length l) O(1)) ) = O(length l) "Fortune" has nothing to do with it - I knew this algorithm was linear all the time and when you identified the linear calls in the body I replaced those and now the implementation is linear as well. >> constant: cons, cdr, nreverse > > No. your call to nreverse is O(length l). Since it is outside of the loop body it doesn't change the "artificial" complexity, but OK: constant: cdr, cons linear: append, butlast, nreverse -- underground experts united http://user.it.uu.se/~embe8573 ^ permalink raw reply [flat|nested] 24+ messages in thread
[parent not found: <mailman.7963.1438986782.904.help-gnu-emacs@gnu.org>]
* Re: How to delete all nil properties from a plist? [not found] ` <mailman.7963.1438986782.904.help-gnu-emacs@gnu.org> @ 2015-08-08 3:56 ` Pascal J. Bourguignon 2015-08-09 1:34 ` Emanuel Berg [not found] ` <mailman.7996.1439084206.904.help-gnu-emacs@gnu.org> 0 siblings, 2 replies; 24+ messages in thread From: Pascal J. Bourguignon @ 2015-08-08 3:56 UTC (permalink / raw) To: help-gnu-emacs Emanuel Berg <embe8573@student.uu.se> writes: > "Pascal J. Bourguignon" <pjb@informatimago.com> > writes: >> NEVER put the then on the same line as the test! > > ... why? because it makes it confusing to read. If you do that, we have to count the parentheses!!! -- __Pascal Bourguignon__ http://www.informatimago.com/ “The factory of the future will have only two employees, a man and a dog. The man will be there to feed the dog. The dog will be there to keep the man from touching the equipment.” -- Carl Bass CEO Autodesk ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: How to delete all nil properties from a plist? 2015-08-08 3:56 ` Pascal J. Bourguignon @ 2015-08-09 1:34 ` Emanuel Berg [not found] ` <mailman.7996.1439084206.904.help-gnu-emacs@gnu.org> 1 sibling, 0 replies; 24+ messages in thread From: Emanuel Berg @ 2015-08-09 1:34 UTC (permalink / raw) To: help-gnu-emacs "Pascal J. Bourguignon" <pjb@informatimago.com> writes: >>> NEVER put the then on the same line as the test! >> >> ... why? > > because it makes it confusing to read. I think it looks good. Often the condition is short (it should be short) so there is plenty of space to use on that line. > If you do that, we have to count the parentheses!!! Why, and when? I have done that all the time and not once counted parentheses: (if nil-prop (setq nil-prop nil) (setq new (cons x new)) ) Try this: ;; parentheses (show-paren-mode t) (defvar show-paren-delay) (setq show-paren-delay 0) -- underground experts united http://user.it.uu.se/~embe8573 ^ permalink raw reply [flat|nested] 24+ messages in thread
[parent not found: <mailman.7996.1439084206.904.help-gnu-emacs@gnu.org>]
* Re: How to delete all nil properties from a plist? [not found] ` <mailman.7996.1439084206.904.help-gnu-emacs@gnu.org> @ 2015-08-09 2:18 ` Pascal J. Bourguignon 2015-08-09 2:28 ` Emanuel Berg 0 siblings, 1 reply; 24+ messages in thread From: Pascal J. Bourguignon @ 2015-08-09 2:18 UTC (permalink / raw) To: help-gnu-emacs Emanuel Berg <embe8573@student.uu.se> writes: > "Pascal J. Bourguignon" <pjb@informatimago.com> > writes: > >>>> NEVER put the then on the same line as the test! >>> >>> ... why? >> >> because it makes it confusing to read. > > I think it looks good. Often the condition is short > (it should be short) so there is plenty of space to > use on that line. > >> If you do that, we have to count the parentheses!!! > > Why, and when? Compare those two forms: (if (and (some-predicate-p a) (= a 1) (print (list a (some-function a)))) (print b)) (if (and (some-predicate-p a) (= a 1)) (print (list a (some-function a))) (print b)) and then compare those two forms: (when (and (some-predicate-p a) (= a 1) (print (list a (some-function a)))) (print b)) (if (and (some-predicate-p a) (= a 1)) (print (list a (some-function a))) (print b)) > I have done that all the time and not once counted > parentheses: > > (if nil-prop (setq nil-prop nil) > (setq new (cons x new)) ) This is very bad style. -- __Pascal Bourguignon__ http://www.informatimago.com/ “The factory of the future will have only two employees, a man and a dog. The man will be there to feed the dog. The dog will be there to keep the man from touching the equipment.” -- Carl Bass CEO Autodesk ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: How to delete all nil properties from a plist? 2015-08-09 2:18 ` Pascal J. Bourguignon @ 2015-08-09 2:28 ` Emanuel Berg 0 siblings, 0 replies; 24+ messages in thread From: Emanuel Berg @ 2015-08-09 2:28 UTC (permalink / raw) To: help-gnu-emacs "Pascal J. Bourguignon" <pjb@informatimago.com> writes: > Compare those two forms: > > (if (and (some-predicate-p a) (= a 1) (print (list a (some-function a)))) > (print b)) > (if (and (some-predicate-p a) (= a 1)) (print (list a (some-function a))) > (print b)) > > > and then compare those two forms: > > (when (and (some-predicate-p a) (= a 1) (print (list a (some-function a)))) > (print b)) > (if (and (some-predicate-p a) (= a 1)) > (print (list a (some-function a))) > (print b)) This problem is not a consequence of writing the "then" branch on the same line but having the condition complicated and too long lines in general. If you don't do neither there is nothing wrong with having not only the "then" branch but *both* branches on the same line: (if long "&filters=long&lclk=long" "") -- underground experts united http://user.it.uu.se/~embe8573 ^ permalink raw reply [flat|nested] 24+ messages in thread
[parent not found: <mailman.7749.1438467076.904.help-gnu-emacs@gnu.org>]
* Re: How to delete all nil properties from a plist? [not found] ` <mailman.7749.1438467076.904.help-gnu-emacs@gnu.org> @ 2015-08-01 23:46 ` Pascal J. Bourguignon 0 siblings, 0 replies; 24+ messages in thread From: Pascal J. Bourguignon @ 2015-08-01 23:46 UTC (permalink / raw) To: help-gnu-emacs Marcin Borkowski <mbork@mbork.pl> writes: > OK, so what about this? Is there a better way (which would probably > mean, is such function already defined)? > > (defun alist-clear (alist) > "Return ALIST with all pairs with nil value deleted." > (if alist Better use when in this case. > (if (cdar alist) > (cons (car alist) > (alist-clear (cdr alist))) The bad thing (shared with your plist-clear) of this, is that it's a non-terminal recursive call, and therefore it will use O(n) stack space with n = (length alist). Ie. it will break for not so long alists. See the variable max-lisp-eval-depth. > (alist-clear (cdr alist))))) -- __Pascal Bourguignon__ http://www.informatimago.com/ “The factory of the future will have only two employees, a man and a dog. The man will be there to feed the dog. The dog will be there to keep the man from touching the equipment.” -- Carl Bass CEO Autodesk ^ permalink raw reply [flat|nested] 24+ messages in thread
[parent not found: <mailman.7748.1438466648.904.help-gnu-emacs@gnu.org>]
* Re: How to delete all nil properties from a plist? [not found] <mailman.7748.1438466648.904.help-gnu-emacs@gnu.org> @ 2015-08-01 23:43 ` Pascal J. Bourguignon 0 siblings, 0 replies; 24+ messages in thread From: Pascal J. Bourguignon @ 2015-08-01 23:43 UTC (permalink / raw) To: help-gnu-emacs Marcin Borkowski <mbork@mbork.pl> writes: > Hi all, > > so I'm still using plists, though I'm less and less sure that they are > actually better than alists for my use-case. Now I need to delete all > properties whose value is nil. I'm using this function: > > (defun plist-clear (plist) > "Return PLIST with all nil properties deleted." > (cond > ((< (length plist) 2) nil) very bad, you walk the list once more. > ((null (cadr plist)) (cddr plist)) ok. > (t (cons (car plist) (cons (cadr plist) (plist-clear (cddr > plist))))))) And since you call plist-clear recursive, the above walk makes it O(n²)! > Question 1: is there a better way to write it? (Especially the last > line.) Yes. (defun plist-clear (plist) "Return PLIST with all nil properties deleted." (loop for (k v) on plist by (function cddr) when v collect k collect v)) > Question 2: how would I do the analogous thing with alists? (defun alist-clear (alist) "Return ALIST with all nil properties deleted." (remove* nil alist :key (function cdr))) -- __Pascal Bourguignon__ http://www.informatimago.com/ “The factory of the future will have only two employees, a man and a dog. The man will be there to feed the dog. The dog will be there to keep the man from touching the equipment.” -- Carl Bass CEO Autodesk ^ permalink raw reply [flat|nested] 24+ messages in thread
end of thread, other threads:[~2015-08-09 2:28 UTC | newest] Thread overview: 24+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2015-08-01 22:03 How to delete all nil properties from a plist? Marcin Borkowski 2015-08-01 22:11 ` Marcin Borkowski 2015-08-02 1:32 ` Emanuel Berg [not found] ` <mailman.7753.1438479312.904.help-gnu-emacs@gnu.org> 2015-08-02 1:36 ` Pascal J. Bourguignon 2015-08-02 1:50 ` Emanuel Berg 2015-08-02 3:55 ` Rusi 2015-08-02 16:21 ` Pascal J. Bourguignon [not found] ` <mailman.7754.1438480361.904.help-gnu-emacs@gnu.org> 2015-08-02 16:24 ` Pascal J. Bourguignon 2015-08-05 23:08 ` Emanuel Berg [not found] ` <mailman.7864.1438816202.904.help-gnu-emacs@gnu.org> 2015-08-05 23:30 ` Pascal J. Bourguignon 2015-08-05 23:49 ` Emanuel Berg 2015-08-06 0:30 ` Emanuel Berg 2015-08-06 1:05 ` John Mastro 2015-08-06 1:07 ` John Mastro [not found] ` <mailman.7867.1438818687.904.help-gnu-emacs@gnu.org> 2015-08-06 2:32 ` Pascal J. Bourguignon 2015-08-07 22:21 ` Emanuel Berg [not found] ` <mailman.7869.1438821124.904.help-gnu-emacs@gnu.org> 2015-08-06 2:40 ` Pascal J. Bourguignon 2015-08-07 22:32 ` Emanuel Berg [not found] ` <mailman.7963.1438986782.904.help-gnu-emacs@gnu.org> 2015-08-08 3:56 ` Pascal J. Bourguignon 2015-08-09 1:34 ` Emanuel Berg [not found] ` <mailman.7996.1439084206.904.help-gnu-emacs@gnu.org> 2015-08-09 2:18 ` Pascal J. Bourguignon 2015-08-09 2:28 ` Emanuel Berg [not found] ` <mailman.7749.1438467076.904.help-gnu-emacs@gnu.org> 2015-08-01 23:46 ` Pascal J. Bourguignon [not found] <mailman.7748.1438466648.904.help-gnu-emacs@gnu.org> 2015-08-01 23:43 ` Pascal J. Bourguignon
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).