Is there an easy way to remove a single element from a list when there
are duplicates of that element?
For example, if I have (1 2 1 3), is it possible to remove just the
second '1' and end up with (1 2 3)?
········@gmail.com writes:
> Is there an easy way to remove a single element from a list when there
> are duplicates of that element?
>
> For example, if I have (1 2 1 3), is it possible to remove just the
> second '1' and end up with (1 2 3)?
Your specification is not really precise.
Do you mean the following?
(defun positions (item list &key (test (function eql)) (key (function identity)))
(loop for i from 0 for x in list
when (funcall test item (funcall key x)) collect i))
(defun remove-nth-occurence-of-item (n item list
&key (test (function eql))
(key (function identity)))
(let ((p (nth n (positions item list :test test :key key))))
(if p
(remove-if (constantly t) list :start p :end (1+ p))
list)))
(remove-nth-occurence-of-item 1 1 '(1 2 1 3))
--
__Pascal Bourguignon__ http://www.informatimago.com/
-----BEGIN GEEK CODE BLOCK-----
Version: 3.12
GCS d? s++:++ a+ C+++ UL++++ P--- L+++ E+++ W++ N+++ o-- K- w---
O- M++ V PS PE++ Y++ PGP t+ 5+ X++ R !tv b+++ DI++++ D++
G e+++ h+ r-- z?
------END GEEK CODE BLOCK------
Sorry for not being clear. I tried to make my example simple and lost
what I was trying to convey.
Basically I need to treat it as an array and remove the nth element.
Something like (my-remove 3 '(a b c d e))
and get (a b c e). The catch is I don't care about duplicates like the
normal remove does.
That is (my-remove 3 '(a a a a b))
should give me (a a a b)
········@gmail.com wrote:
> Sorry for not being clear. I tried to make my example simple and lost
> what I was trying to convey.
>
> Basically I need to treat it as an array and remove the nth element.
>
> Something like (my-remove 3 '(a b c d e))
> and get (a b c e). The catch is I don't care about duplicates like the
> normal remove does.
>
> That is (my-remove 3 '(a a a a b))
> should give me (a a a b)
Something like the following?
(defun my-remove (nth list)
(remove-if (constantly t)
list
:start nth :count 1))
No doubt there's something more eloquent, but it escapes me at the
moment...
Tayssir
Tayssir John Gabbour wrote:
> Something like the following?
>
> (defun my-remove (nth list)
> (remove-if (constantly t)
> list
> :start nth :count 1))
>
> No doubt there's something more eloquent, but it escapes me at the
> moment...
That's a nice one! Of course remove-if would have this functionality.
I've got to stop going to LOOP first, and start reading the hyperspec :)
drewc
--
Drew Crampsie
drewc at tech dot coop
"Never mind the bollocks -- here's the sexp's tools."
-- Karl A. Krueger on comp.lang.lisp
On 20 Sep 2005 11:39:45 -0700, ········@gmail.com tried to confuse
everyone with this message:
>Sorry for not being clear. I tried to make my example simple and lost
>what I was trying to convey.
>
>Basically I need to treat it as an array and remove the nth element.
>
>Something like (my-remove 3 '(a b c d e))
>and get (a b c e). The catch is I don't care about duplicates like the
>normal remove does.
>
>That is (my-remove 3 '(a a a a b))
>should give me (a a a b)
>
Something like
(defun my-remove (n list)
(cons (butlast list (- (length list) n 1)) (nthcdr (1+ n) list)))
--
|a\o/r|,-------------.,---------- Timofei Shatrov aka Grue ------------.
| m"a ||FC AMKAR PERM|| mail: grue at mail.ru http://grue3.tripod.com |
| k || PWNZ J00 || Kingdom of Loathing: Grue3 lvl 18 Seal Clubber |
`-----'`-------------'`-------------------------------------------[4*72]
····@mail.ru (Timofei Shatrov) writes:
> On 20 Sep 2005 11:39:45 -0700, ········@gmail.com tried to confuse
> everyone with this message:
>
>>Sorry for not being clear. I tried to make my example simple and lost
>>what I was trying to convey.
>>
>>Basically I need to treat it as an array and remove the nth element.
>>
>>Something like (my-remove 3 '(a b c d e))
>>and get (a b c e). The catch is I don't care about duplicates like the
>>normal remove does.
>>
>>That is (my-remove 3 '(a a a a b))
>>should give me (a a a b)
>>
>
> Something like
> (defun my-remove (n list)
> (cons (butlast list (- (length list) n 1)) (nthcdr (1+ n) list)))
One should never pass up an opportunity to use LDIFF:
(defun my-remove (n list)
(let ((tail (nthcdr n list)))
(nconc (ldiff list tail) (rest tail))))
Note this is non-destructive (a.k.a. non-recycling) despite the use of
NCONC since LDIFF returns (as it must) new list structure. It does, of
course, return a list that may share structure with the original list.
-Peter
--
Peter Seibel * ·····@gigamonkeys.com
Gigamonkeys Consulting * http://www.gigamonkeys.com/
Practical Common Lisp * http://www.gigamonkeys.com/book/
········@gmail.com wrote:
> Sorry for not being clear. I tried to make my example simple and lost
> what I was trying to convey.
>
> Basically I need to treat it as an array and remove the nth element.
>
> Something like (my-remove 3 '(a b c d e))
> and get (a b c e). The catch is I don't care about duplicates like the
> normal remove does.
This should do what you want (assuming you have actually specified what
you want)
1) using loop :
CL> (defun remove-nth (number list)
(append (loop for n upto (1- number)
for i in list
collect i)
(nthcdr (1+ number) list)))
REMOVE-NTH
Or a destructive version using rplacd :
CL> (defun delete-nth (number list)
(prog2
(rplacd (nthcdr (1- number) list)
(nthcdr (1+ number) list))
list))
DELETE-NTH
Or a recursive translation :
CL> (defun r-remove-nth (number list &optional new-list (count 0))
(if (< count number)
(r-remove-nth number (cdr list)
(cons (car list) new-list)
(1+ count))
(append (reverse new-list) (cdr list))))
And the results :
CL> (remove-nth 3 (list 0 1 2 3 4 5))
(0 1 2 4 5)
CL> (delete-nth 3 (list 0 1 2 3 4 5))
(0 1 2 4 5)
CL> (r-remove-nth 3 (list 0 1 2 3 4 5))
(0 1 2 4 5)
CL>
HTH.
--
Drew Crampsie
drewc at tech dot coop
"Never mind the bollocks -- here's the sexp's tools."
-- Karl A. Krueger on comp.lang.lisp
drewc wrote:
> ········@gmail.com wrote:
>
>> Sorry for not being clear. I tried to make my example simple and lost
>> what I was trying to convey.
>>
>> Basically I need to treat it as an array and remove the nth element.
>>
>> Something like (my-remove 3 '(a b c d e))
>> and get (a b c e). The catch is I don't care about duplicates like the
>> normal remove does.
And, FWIW, this last version is faster and conses less than all the
non-destuctive versions in this thread so far (at least on SBCL x86 linux) :
CL> (defun l-remove-nth (nth list)
(loop for x upfrom 0
for i in list
with new-list
do (unless (eql x nth)
(setf new-list (cons i new-list)))
finally (return (nreverse new-list))))
Can you tell i love loop? :)
drewc
>
>
> This should do what you want (assuming you have actually specified what
> you want)
>
> 1) using loop :
>
> CL> (defun remove-nth (number list)
> (append (loop for n upto (1- number)
> for i in list
> collect i)
> (nthcdr (1+ number) list)))
> REMOVE-NTH
>
> Or a destructive version using rplacd :
>
> CL> (defun delete-nth (number list)
> (prog2
> (rplacd (nthcdr (1- number) list)
> (nthcdr (1+ number) list))
> list))
> DELETE-NTH
>
>
> Or a recursive translation :
>
> CL> (defun r-remove-nth (number list &optional new-list (count 0))
> (if (< count number)
> (r-remove-nth number (cdr list)
> (cons (car list) new-list)
> (1+ count))
> (append (reverse new-list) (cdr list))))
>
>
> And the results :
>
> CL> (remove-nth 3 (list 0 1 2 3 4 5))
> (0 1 2 4 5)
> CL> (delete-nth 3 (list 0 1 2 3 4 5))
> (0 1 2 4 5)
> CL> (r-remove-nth 3 (list 0 1 2 3 4 5))
> (0 1 2 4 5)
> CL>
>
> HTH.
>
>
--
Drew Crampsie
drewc at tech dot coop
"Never mind the bollocks -- here's the sexp's tools."
-- Karl A. Krueger on comp.lang.lisp
justinhj wrote:
> Is your last loop one faster than your destructive version using
> rplacd?
Not by a long shot. I get between 8 and 12 seconds for the
loop/recursive versions, and just above 3 for the rplacd (i'm simply
doing about 10 million iterations of the test provided by the OP).
drewc
--
Drew Crampsie
drewc at tech dot coop
"Never mind the bollocks -- here's the sexp's tools."
-- Karl A. Krueger on comp.lang.lisp
I guess that's what you'd expect.
I came up with this non-destructive version, which I quite like.
(defun remove-nth(n lst)
(if (> n 0)
(cons (car lst)
(remove-nth (1- n) (cdr lst)))
(cdr lst)))
Although I haven't thought of an elegant way to detect that input n is
greater than the length of the list. The implemetation adds (length -
n) nils to the end of the list if it's not long enough.
"justinhj" <········@gmail.com> writes:
>
> Although I haven't thought of an elegant way to detect that input n is
> greater than the length of the list. The implemetation adds (length -
> n) nils to the end of the list if it's not long enough.
Just test the list argument for being NIL.
--
Thomas A. Russ, USC/Information Sciences Institute
This is what came to mind but it seems a shame to take the cdr of list
twice
(defun remove-nth(n lst)
(if (eql (cdr lst) nil)
nil
(if (> n 0)
(cons (car lst)
(remove-nth (1- n) (cdr lst)))
(cdr lst))))
justinhj wrote:
> Although I haven't thought of an elegant way to detect that input n is
> greater than the length of the list. The implemetation adds (length -
> n) nils to the end of the list if it's not long enough.
>
Ah good point! the second test should take care of that :
(defun remove-nth (nth list &optional new-list)
(cond ((eql nth 0)
(nconc (nreverse new-list) (cdr list)))
((eql nil list)
(nreverse new-list))
(t
(remove-nth (1- nth)
(cdr list) (cons (car list) new-list)))))
and there you go. I hope the OP is still with us :)
--
Drew Crampsie
drewc at tech dot coop
"Never mind the bollocks -- here's the sexp's tools."
-- Karl A. Krueger on comp.lang.lisp
justinhj writes:
> Although I haven't thought of an elegant way to detect that input n
> is greater than the length of the list. The implemetation adds
> (length -
> n) nils to the end of the list if it's not long enough.
~% sbcl
This is SBCL 0.8.16, an implementation of ANSI Common Lisp.
More information about SBCL is available at <http://www.sbcl.org/>.
SBCL is free software, provided as is, with absolutely no warranty.
It is mostly in the public domain; some portions are provided under
BSD-style licenses. See the CREDITS and COPYING files in the
distribution for more information.
* (defun remove-nth (n lst)
(if (or (= n 0) (null lst))
(cdr lst)
(cons (car lst) (remove-nth (1- n) (cdr lst)))))
REMOVE-NTH
* (remove-nth 0 (list 0 1 2 3 4 5))
(1 2 3 4 5)
* (remove-nth 3 (list 0 1 2 3 4 5))
(0 1 2 4 5)
* (remove-nth 8 (list 0 1 2 3 4 5))
(0 1 2 3 4 5)
*
justinhj wrote:
> I guess that's what you'd expect.
>
> I came up with this non-destructive version, which I quite like.
>
> (defun remove-nth(n lst)
> (if (> n 0)
> (cons (car lst)
> (remove-nth (1- n) (cdr lst)))
> (cdr lst)))
Much nicer than mine, which was a poor translation of a hacked loop
(hadn't had my coffee yet) :)
Here is a tail recursive version :
(defun remove-nth (nth list &optional new-list)
(cond ((eql nth 0)
(nconc (nreverse new-list) (cdr list)))
(t
(remove-nth (1- nth) (cdr list)
(cons (car list) new-list)))))
which runs close to the speed of my LOOP abuse, and conses a lot less.
This is one on my favourite "features" of common lisp .. that i can
throw something together that barely works, and come back in the
afternoon to fine tune it. LOOP is a fine example of this. I often hack
up quick solution using loop, and later come back and replace it with a
recursive solution, when the problem is more clear to me. Or start with
alists and move to CLOS.
While the above is certainly more idiomatic, I had to think more than 5
minutes about it , and there are other problems to be solved!
--
Drew Crampsie
drewc at tech dot coop
"Never mind the bollocks -- here's the sexp's tools."
-- Karl A. Krueger on comp.lang.lisp
Hello,
drewc <·····@rift.com> writes:
> drewc wrote:
>> ········@gmail.com wrote:
>>
>>> Sorry for not being clear. I tried to make my example simple and lost
>>> what I was trying to convey.
>>>
>>> Basically I need to treat it as an array and remove the nth element.
>>>
>>> Something like (my-remove 3 '(a b c d e))
>>> and get (a b c e). The catch is I don't care about duplicates like the
>>> normal remove does.
>
> And, FWIW, this last version is faster and conses less than all the
> non-destuctive versions in this thread so far (at least on SBCL x86 linux) :
>
> CL> (defun l-remove-nth (nth list)
> (loop for x upfrom 0
> for i in list
> with new-list
> do (unless (eql x nth)
> (setf new-list (cons i new-list)))
> finally (return (nreverse new-list))))
>
> Can you tell i love loop? :)
What about:
,----
| (defun remove-nth (nth list)
| (loop :for index :from 0
| :for item :in list
| :unless (= index nth)
| :collect item))
`----
> drewc
Cu,
Damien.
--
http://foobox.net/~dash/
I can resist everything except temptation.
--Oscar Wilde