I am trying to implement a function which will remove the common items
in two lists and if there're no common items, it'll return the
original list.
Here's the code that I have written but it's not not returning the
modified list...
(defun remove-visited (list1 list2)
(let ((temp list2))
(dolist (x list1)
(if (not (null (find x list2 :test #'equal)))
(remove x temp :test #'equal)
(print temp)))))
Can anyone help me..
On Apr 9, 7:28 pm, ···········@gmail.com wrote:
> I am trying to implement a function which will remove the common items
> in two lists and if there're no common items, it'll return the
> original list.
>
> Here's the code that I have written but it's not not returning the
> modified list...
> (defun remove-visited (list1 list2)
> (let ((temp list2))
> (dolist (x list1)
> (if (not (null (find x list2 :test #'equal)))
> (remove x temp :test #'equal)
> (print temp)))))
>
> Can anyone help me..
Got the better one.
(set-difference list2 list1)
Hail Lisp(y)..!
On Apr 9, 7:33 pm, ···········@gmail.com wrote:
> On Apr 9, 7:28 pm, ···········@gmail.com wrote:
>
> > I am trying to implement a function which will remove the common items
> > in two lists and if there're no common items, it'll return the
> > original list.
>
> > Here's the code that I have written but it's not not returning the
> > modified list...
> > (defun remove-visited (list1 list2)
> > (let ((temp list2))
> > (dolist (x list1)
> > (if (not (null (find x list2 :test #'equal)))
> > (remove x temp :test #'equal)
> > (print temp)))))
>
> > Can anyone help me..
>
> Got the better one.
> (set-difference list2 list1)
>
> Hail Lisp(y)..!
Alas! I was not able to do it. Somebody please help me out.
In article
<····································@a70g2000hsh.googlegroups.com>,
···········@gmail.com wrote:
> On Apr 9, 7:33 pm, ···········@gmail.com wrote:
> > On Apr 9, 7:28 pm, ···········@gmail.com wrote:
> >
> > > I am trying to implement a function which will remove the common items
> > > in two lists and if there're no common items, it'll return the
> > > original list.
> >
> > > Here's the code that I have written but it's not not returning the
> > > modified list...
> > > (defun remove-visited (list1 list2)
> > > (let ((temp list2))
> > > (dolist (x list1)
> > > (if (not (null (find x list2 :test #'equal)))
> > > (remove x temp :test #'equal)
> > > (print temp)))))
> >
> > > Can anyone help me..
> >
> > Got the better one.
> > (set-difference list2 list1)
> >
> > Hail Lisp(y)..!
>
> Alas! I was not able to do it. Somebody please help me out.
Try (set-difference list2 list1 :test #'equal)
The problem with your original code is that you need to assign the
result of REMOVE back to TEMP, i.e.
(setq temp (remove x temp :test #'equal))
Also, there's no need to call FIND first. If x isn't in TEMP, REMOVE
won't do anything.
--
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE don't copy me on replies, I'll read them in the group ***
Barry Margolin <······@alum.mit.edu> writes:
> In article
> <····································@a70g2000hsh.googlegroups.com>,
> ···········@gmail.com wrote:
>
>> On Apr 9, 7:33 pm, ···········@gmail.com wrote:
>> > On Apr 9, 7:28 pm, ···········@gmail.com wrote:
>> >
>> > > I am trying to implement a function which will remove the common items
>> > > in two lists and if there're no common items, it'll return the
>> > > original list.
>> >
>> > > Here's the code that I have written but it's not not returning the
>> > > modified list...
>> > > (defun remove-visited (list1 list2)
>> > > (let ((temp list2))
>> > > (dolist (x list1)
>> > > (if (not (null (find x list2 :test #'equal)))
>> > > (remove x temp :test #'equal)
>> > > (print temp)))))
>> >
>> > > Can anyone help me..
>> >
>> > Got the better one.
>> > (set-difference list2 list1)
>> >
>> > Hail Lisp(y)..!
>>
>> Alas! I was not able to do it. Somebody please help me out.
>
> Try (set-difference list2 list1 :test #'equal)
>
> The problem with your original code is that you need to assign the
> result of REMOVE back to TEMP, i.e.
>
> (setq temp (remove x temp :test #'equal))
>
> Also, there's no need to call FIND first. If x isn't in TEMP, REMOVE
> won't do anything.
Or:
(defun remove-members (list remove &key (test #'eql) (key #'identity))
(remove-if #'(lambda (x) (member x remove :test test :key key))
list :key key))
No SETQ's needed, and it has a better name. ;)
···········@gmail.com writes:
> I am trying to implement a function which will remove the common items
> in two lists and if there're no common items, it'll return the
> original list.
>
> Here's the code that I have written but it's not not returning the
> modified list...
> (defun remove-visited (list1 list2)
> (let ((temp list2))
> (dolist (x list1)
> (if (not (null (find x list2 :test #'equal)))
> (remove x temp :test #'equal)
> (print temp)))))
>
> Can anyone help me..
There were a number of improvement suggestions, but I didn't see an
answer explaining what is wrong with your code.
In a nutshell, there are two problems:
1. You never recorde the results of the REMOVE function application.
2. You never return a reasonable value from your routine.
2a. Your DOLIST is not specified to return anything, so you get NIL
2b. You don't return any other value from LET, so you just get NIL.
So, a very simple re-write or your program would look like the
following. Note that I also removed the (NOT (NULL ...)) since that is
a redundant construction.
(defun remove-visited (list1 list2)
(let ((temp list2))
(dolist (x list1)
(if (find x list2 :test #'equal)
(setf temp (remove x temp :test #'equal))
(print temp)))
temp))
I would also note that there isn't really any point in doing your FIND
test against the original list2 instead of temp. So that means you can,
in fact, dispense with the temporary variable altogether and just use
LIST2, since it is bound by the parameter call. I've also change the IF
into a WHEN and dropped the printing if no match is found.
(defun remove-visited (list1 list2)
(dolist (x list1)
(when (find x list2 :test #'equal)
(setf list2 (remove x list2 :test #'equal))))
list2)
Now, you can simplify this even more by realizing that remove doesn't
hurt if there is no match:
(defun remove-visited (list1 list2)
(dolist (x list1)
(setf list2 (remove x list2 :test #'equal)))
list2)
And there you have a much simplified version of the code. Of course, as
someone else pointed out, the simplest implementation is to just use the
built-in function:
(set-difference list2 list1 :test #'equal)
--
Thomas A. Russ, USC/Information Sciences Institute
···········@gmail.com writes:
> I am trying to implement a function which will remove the common items
> in two lists and if there're no common items, it'll return the
> original list.
>
> Here's the code that I have written but it's not not returning the
> modified list...
> (defun remove-visited (list1 list2)
> (let ((temp list2))
> (dolist (x list1)
> (if (not (null (find x list2 :test #'equal)))
> (remove x temp :test #'equal)
> (print temp)))))
>
> Can anyone help me..
Chose pungent variable names, not generic ones
CL-USER> (defun purify-data (unwashed-list dirty-list)
(let (clean-list)
(dolist (item unwashed-list clean-list)
(unless (member item dirty-list)
(push item clean-list)))))
PURIFY-DATA
CL-USER> (purify-data '(a b c d e) '(b d))
(E C A)
CL-USER> (defun keep-unseen (all seen)
(let (unseen)
(dolist (node all unseen)
(unless (find node seen)
(push node unseen)))))
KEEP-UNSEEN
CL-USER> (keep-unseen '(a b c d e) '(b d))
(E C A)
Obviously one can go too far
CL-USER> (defun purge (suspect black-list)
"list reliable comrades"
(let (reliable)
;; Check all suspect comrades against the blacklist
;; returning the reliable ones
(dolist (comrade suspect reliable)
(unless (find comrade black-list)
(push comrade reliable)))))
PURGE
CL-USER> (purge '(a b c d e) '(b d))
(E C A)
Actually it is not clear to me that "going too far" does any
real harm. I'm guilty of using generic names. Sometimes I
make a bit of an effort to choose more suggestive names and
it always pays off. Has any-one actually overdone it on real
code, permitting them to say "it hurts you like this ..."
Alan Crowe
Edinburgh
Scotland
From: Kent M Pitman
Subject: Re: Remove-common function in Lisp
Date:
Message-ID: <uzls0o59w.fsf@nhplace.com>
Alan Crowe <····@cawtech.freeserve.co.uk> writes:
> CL-USER> (defun purge (suspect black-list)
> "list reliable comrades"
> (let (reliable)
> ;; Check all suspect comrades against the blacklist
> ;; returning the reliable ones
> (dolist (comrade suspect reliable)
> (unless (find comrade black-list)
> (push comrade reliable)))))
> PURGE
>
> CL-USER> (purge '(a b c d e) '(b d))
> (E C A)
>
> Actually it is not clear to me that "going too far" does any
> real harm. I'm guilty of using generic names. Sometimes I
> make a bit of an effort to choose more suggestive names and
> it always pays off. Has any-one actually overdone it on real
> code, permitting them to say "it hurts you like this ..."
Well, there are certainly ways you can run afoul of things. You can
confuse and side-track people with overly obscure metaphors:
(defun purge (dromedary newsgroup) ...)
and can offend people with others [I'll let you use your imagination
there].
You could even lay a trap where a confusion that comes later, as in:
(defpackage "CROWE-UTILS"
(:export "PURGE"))
...
(defpackage "CRIME-SCENE-INVESTIGATION"
(:nicknames "CSI")
(:use "CROWE-UTILS"))
(in-package "CSI")
(defclass suspect ...)
and then someone starts to type "(purge" and presses control-shift-A
in Emacs to see what the arglist of purge is and finds he must give
a SUSPECT as a first argument. That could confuse your user as to whether
that's a role or an actual instantiable object. Hard to see how to predict
that this was coming unless you want to bet against the success and broad
use of your program. Even just
(defun cons (car cdr) ...)
in an automobile factory could cause a bit of consternation if you assume
the only knowledge the programmer has is of cars and none of Lisp. I guess
the whole point of understanding packages is to help people come to grips
with the fact that these things happen.
One slightly more substantive risk is not "going too far" but picking
a word that appears to have extra out-of-band meaning. In your
example, you suggest a metaphor of a system in which there was a
suspect and a black-list, but such societies (we have one now) do lots
of record-keeping, and this could cause someone to believe there was
not just functional effect but memory [persistent state beyond the
call] involved in "reporting" a suspect. (Maybe a minor stretch in
this example, but easily within the realm of reason in other
applications I've seen.) So pick your metaphor carefully to convey
the extra baggage you want and not the baggage you don't.
On the whole, I think these pitfalls are usually worth the risk, and I
agree that a robust metaphor is often best. Leadership is about
establishing a vision. You can change the vision if it turns out not
to work out, but it's useful to have something clear you're rallying to.
Alan Crowe <····@cawtech.freeserve.co.uk> writes:
> ···········@gmail.com writes:
>
>> I am trying to implement a function which will remove the common items
>> in two lists and if there're no common items, it'll return the
>> original list.
>>
>> Here's the code that I have written but it's not not returning the
>> modified list...
>> (defun remove-visited (list1 list2)
>> (let ((temp list2))
>> (dolist (x list1)
>> (if (not (null (find x list2 :test #'equal)))
>> (remove x temp :test #'equal)
>> (print temp)))))
>>
>> Can anyone help me..
>
> Chose pungent variable names, not generic ones
>
> CL-USER> (defun purify-data (unwashed-list dirty-list)
> (let (clean-list)
> (dolist (item unwashed-list clean-list)
> (unless (member item dirty-list)
> (push item clean-list)))))
> PURIFY-DATA
>
> CL-USER> (purify-data '(a b c d e) '(b d))
> (E C A)
>
> CL-USER> (defun keep-unseen (all seen)
> (let (unseen)
> (dolist (node all unseen)
> (unless (find node seen)
> (push node unseen)))))
> KEEP-UNSEEN
>
> CL-USER> (keep-unseen '(a b c d e) '(b d))
> (E C A)
>
> Obviously one can go too far
>
> CL-USER> (defun purge (suspect black-list)
> "list reliable comrades"
> (let (reliable)
> ;; Check all suspect comrades against the blacklist
> ;; returning the reliable ones
> (dolist (comrade suspect reliable)
> (unless (find comrade black-list)
> (push comrade reliable)))))
> PURGE
>
> CL-USER> (purge '(a b c d e) '(b d))
> (E C A)
>
> Actually it is not clear to me that "going too far" does any
> real harm. I'm guilty of using generic names. Sometimes I
> make a bit of an effort to choose more suggestive names and
> it always pays off. Has any-one actually overdone it on real
> code, permitting them to say "it hurts you like this ..."
Depends on whether you're writting a very specific function for the
problem at hand, or if you're writting a utility function. In the
former case, I agree that pungent names are the right thing. In the
later case, the problem is different:
(defclass sequence () (...))
(defclass vector (sequence) (...))
(defclass string (vector) (...))
(defun purge (string black-bag) ; <--- gone too far
(let ((result (make-vector 0 :adjustable t :fill-pointer 0)))
(dotimes (i (length string) result)
(unless (position (aref string i) black-bag)
(vector-push-extend (aref string i) result)))))
(defun purge (sequence black-bag) ; <--- not gone far enough
(let ((result (make-vector 0 :adjustable t :fill-pointer 0)))
(dotimes (i (length string) result)
(unless (position (aref string i) black-bag)
(vector-push-extend (aref string i) result)))))
(defun purge (vector black-bag) ; <--- gone the precise distance
(let ((result (make-vector 0 :adjustable t :fill-pointer 0)))
(dotimes (i (length string) result)
(unless (position (aref string i) black-bag)
(vector-push-extend (aref string i) result)))))
What I mean is that sometimes a more generic term is more pungent.
--
__Pascal Bourguignon__