I repeatedly find myself in trouble when I need to do list processing
that involves dealing with multiple values at once. For example,
consider a function that takes an argument list and removes a
particular keyword parameter:
(remove-keyword-parameter '(1 :a 1 :b 2 :c 3) :b)
=> (1 :a 1 :c 3)
What's an elegant functional (and/or lispy) solution to this problem?
The solution I came up with is, IMO, very convoluted:
(defun remove-keyword-parameter (parameter-list keyword)
(let (remove)
(loop for i in parameter-list
when (eql i keyword)
do (setf remove t)
else when remove
do (setf remove nil)
else unless remove
collect i)))
Could someone suggest a better way?
--
Regards,
Slava Akhmechet.
On 12 Jun., 08:34, Slava Akhmechet <·········@gmail.com> wrote:
> I repeatedly find myself in trouble when I need to do list processing
> that involves dealing with multiple values at once. For example,
> consider a function that takes an argument list and removes a
> particular keyword parameter:
>
> (remove-keyword-parameter '(1 :a 1 :b 2 :c 3) :b)
> => (1 :a 1 :c 3)
>
> What's an elegant functional (and/or lispy) solution to this problem?
> The solution I came up with is, IMO, very convoluted:
>
How about some straightforward recursion?
(defun remove-keyword-parameter (alist key)
(cond
((null alist) nil)
((not (keywordp (first alist))) ;; as the list might as well
contain single variables
(cons (first alist)
(remove-keyword-parameter (rest alist) key)))
((eq key (first alist))
(remove-keyword-parameter (rest (rest alist)) key))
(t (append (list (first alist) (second alist))
(remove-keyword-parameter (rest (rest alist)) key)))))
Cheers, Christoph
Slava Akhmechet <·········@gmail.com> writes:
> I repeatedly find myself in trouble when I need to do list processing
> that involves dealing with multiple values at once. For example,
> consider a function that takes an argument list and removes a
> particular keyword parameter:
>
> (remove-keyword-parameter '(1 :a 1 :b 2 :c 3) :b)
> => (1 :a 1 :c 3)
>
> What's an elegant functional (and/or lispy) solution to this problem?
> The solution I came up with is, IMO, very convoluted:
>
> (defun remove-keyword-parameter (parameter-list keyword)
> (let (remove)
> (loop for i in parameter-list
> when (eql i keyword)
> do (setf remove t)
> else when remove
> do (setf remove nil)
> else unless remove
> collect i)))
>
> Could someone suggest a better way?
No one has yet suggested this (which may indicate it's problematic in
some way), but here's a quick and dirty solution:
(defun remove-keyword-parameter (parameter-list keyword)
(let ((copy (copy-list parameter-list)))
(remf (rest copy) keyword)
copy))
This has the advantage over the function above of handling cases in
which the same list elements can be appear as keys or values.
Slava Akhmechet wrote:
> I repeatedly find myself in trouble when I need to do list processing
> that involves dealing with multiple values at once. For example,
> consider a function that takes an argument list and removes a
> particular keyword parameter:
>
> (remove-keyword-parameter '(1 :a 1 :b 2 :c 3) :b)
> => (1 :a 1 :c 3)
>
> What's an elegant functional (and/or lispy) solution to this problem?
> The solution I came up with is, IMO, very convoluted:
>
> (defun remove-keyword-parameter (parameter-list keyword)
> (let (remove)
> (loop for i in parameter-list
> when (eql i keyword)
> do (setf remove t)
> else when remove
> do (setf remove nil)
> else unless remove
> collect i)))
>
> Could someone suggest a better way?
(loop for (key value) on plist by #'cddr
unless (eql key keyword)
nconc (list key value))
Pascal
--
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
Pascal Costanza escribi�:
> Slava Akhmechet wrote:
>>
>> Could someone suggest a better way?
>
> (loop for (key value) on plist by #'cddr
> unless (eql key keyword)
> nconc (list key value))
>
>
> Pascal
>
Hi,
It's nice, but it won't work with the test case the OP posted, because
the first parameter is not a plist:
(defun remove-keyword-parameter (plist keyword)
(loop for (key value) on plist by #'cddr
unless (eql key keyword)
nconc (list key value)))
CL-USER> (remove-keyword-parameter '(1 :a 1 :b 2 :c 3) :b)
(1 :A 1 :B 2 :C 3 NIL)
Leandro
Slava Akhmechet <·········@gmail.com> writes:
> (remove-keyword-parameter '(1 :a 1 :b 2 :c 3) :b)
> => (1 :a 1 :c 3)
>
> What's an elegant functional (and/or lispy) solution to this problem?
> The solution I came up with is, IMO, very convoluted:
Not simple, but efficient:
http://groups.google.de/group/comp.lang.lisp/browse_thread/thread/4e8451c55102f4df/2520fe9bc7749328?lnk=gst&q=naggum+sans+macro&rnum=1&hl=de#2520fe9bc7749328
Yours, Nicolas
Nicolas Neuss <········@mathematik.uni-karlsruhe.de> writes:
> http://groups.google.de/group/comp.lang.lisp.. (very long)
And this link does probably work better:
http://groups.google.de/group/comp.lang.lisp/msg/2520fe9bc7749328
Nicolas
Slava Akhmechet <·········@gmail.com> writes:
> I repeatedly find myself in trouble when I need to do list processing
> that involves dealing with multiple values at once. For example,
> consider a function that takes an argument list and removes a
> particular keyword parameter:
>
> (remove-keyword-parameter '(1 :a 1 :b 2 :c 3) :b)
> => (1 :a 1 :c 3)
>
> What's an elegant functional (and/or lispy) solution to this problem?
Here is a CL industrial grime solution that uses an obscure
but standard function.
CL-USER> (defun omit (key plist)
(multiple-value-bind (key value tail)
(get-properties plist (list key))
(declare (ignore key value))
(append (ldiff plist tail)
(cddr tail))))
OMIT
CL-USER> (omit :b '(:A 1 :b 2 :c 3))
(:A 1 :C 3)
Alan Crowe
Edinburgh
Scotland
On Tue, 12 Jun 2007 06:34:11 GMT, Slava Akhmechet <·········@gmail.com> said:
| ...
| consider a function that takes an argument list and removes a
| particular keyword parameter:
| (remove-keyword-parameter '(1 :a 1 :b 2 :c 3) :b)
| => (1 :a 1 :c 3)
1. How is it determined where the keyword parameters start?
2. What do e.g. the following return:
(remove-keyword-parameter '(:b :a 1 :b 2 :c 3) :b)
(remove-keyword-parameter '(1 :a 1 :b) :b)
(remove-keyword-parameter '(:b :b 2 :c 3) :b)
---Vassil.
--
The truly good code is the obviously correct code.
From: Kent M Pitman
Subject: Re: Improving coding style - lisp processing
Date:
Message-ID: <u1wgga92v.fsf@nhplace.com>
Vassil Nikolov <···············@pobox.com> writes:
> On Tue, 12 Jun 2007 06:34:11 GMT, Slava Akhmechet <·········@gmail.com> said:
> | ...
> | consider a function that takes an argument list and removes a
> | particular keyword parameter:
>
> | (remove-keyword-parameter '(1 :a 1 :b 2 :c 3) :b)
> | => (1 :a 1 :c 3)
>
> 1. How is it determined where the keyword parameters start?
>
> 2. What do e.g. the following return:
> (remove-keyword-parameter '(:b :a 1 :b 2 :c 3) :b)
> (remove-keyword-parameter '(1 :a 1 :b) :b)
> (remove-keyword-parameter '(:b :b 2 :c 3) :b)
Wow, I'm glad someone finally noticed this! I couldn't believe
everyone was just talking past it. Not that it's not hard to come up with
a theory, but you're right that there are several ways it could be done.
Incidentally, as an aside, it's worth mentioning just for counterpoint
that the following result is kind of fun even though only partly on-topic.
This isn't offered as a real solution so much as a chance to provoke a few
people who don't know about this feature to read up on it for the few cases
where it would work:
(defun lazy-alternative-to-removing-keyword-parameter (parameter-list keyword)
(declare (ignore keyword))
(list* :allow-other-keys t parameter-list))
Using that as a base, and going back to the questions Vassil asks:
The stated example had a 1 at the start of the list, suggesting there
were some preceding arguments. So I'm assuming the so-called
parameter-list is really "the list of keyword parameters after you've
cdr'd past the non-keyword ones".) To really handle that, you'd want,
at minimum some way to know how many positional args; the easy way is
just to pass that as an argument, and in most cases that'd be fine.
(The only alternative that springs to mind other than that is to take
and interpret an arglist, but that's a minor pain and in fact overkill
given the information this really needs is much simpler.)
(defun lazy-alternative-to-removing-keyword-parameter (parameter-list keyword
&optional (offset 0))
(declare (ignore keyword))
(append (firstn offset parameter-list)
(list* :allow-other-keys t (nthcdr offset parameter-list))))
if only you had a firstn function. But I'm sure that's easy enough
for people to crank out (if they don't already have it in a personal
library) that it's not worth showing here.
There's a way to do this with a single loop statement, too, but I'll
spare you. Gotta leave something to the imagination.
Even if you think I'm cheating by using :allow-other-keys, at least
the offset technique can be used for skipping the other args.
Kent M Pitman wrote:
> Vassil Nikolov <···············@pobox.com> writes:
>> On Tue, 12 Jun 2007 06:34:11 GMT, Slava Akhmechet <·········@gmail.com> said:
>> | consider a function that takes an argument list and removes a
>> | particular keyword parameter
>> 2. What do e.g. the following return:
>> (remove-keyword-parameter '(:b :a 1 :b 2 :c 3) :b)
>> (remove-keyword-parameter '(1 :a 1 :b) :b)
>> (remove-keyword-parameter '(:b :b 2 :c 3) :b)
>
> Wow, I'm glad someone finally noticed this! I couldn't believe
> everyone was just talking past it.
Actually, all of the non-plist responses work as long as
the target keyword is followed by a value, and it's easy
to add a case for no value.
--
Dan
www.prairienet.org/~dsb/
On Wed, 13 Jun 2007 06:34:56 -0500, Dan Bensen <··········@cyberspace.net> said:
| Kent M Pitman wrote:
|| Vassil Nikolov <···············@pobox.com> writes:
||| On Tue, 12 Jun 2007 06:34:11 GMT, Slava Akhmechet <·········@gmail.com> said:
||| | consider a function that takes an argument list and removes a
||| | particular keyword parameter
||| 2. What do e.g. the following return:
||| (remove-keyword-parameter '(:b :a 1 :b 2 :c 3) :b)
||| (remove-keyword-parameter '(1 :a 1 :b) :b)
||| (remove-keyword-parameter '(:b :b 2 :c 3) :b)
|| Wow, I'm glad someone finally noticed this! I couldn't believe
|| everyone was just talking past it.
| Actually, all of the non-plist responses work as long as
| the target keyword is followed by a value, and it's easy
| to add a case for no value.
Well, perhaps they do, but I'd still like to know exactly what it
means for them to work in this context. The half dozen or so
implementations that were posted do not all produce equal results
for all cases, but that may or may not matter depending on the
description of the problem. This obviously relates also to Kent
Pitman's post about describing a problem separately from describing
a (suggested) solution.
---Vassil.
--
The truly good code is the obviously correct code.