Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Removing Strings from a list

72 views
Skip to first unread message

Dustin Withers

unread,
Oct 6, 2006, 2:35:07 PM10/6/06
to
Hello All,

My first attempt at this hasn't worked and I was hoping for some
insight. I'm trying to remove all string from a list and return them
as a list.

This is my first attempt:
(let ((elements ()))
(dolist item *LIST*
(if (stringp item)
(push (pop *LIST*) elements)
()))
elements)

What is wrong with this? It causes the error:

Execution of a form compiled with errors.
Form:
(DOLIST ITEM
*LIST*
(IF (STRINGP ITEM) (PUSH (POP *LIST*) ELEMENTS)))
Compile-time error:
(in macroexpansion of (DOLIST ITEM *LIST* ...))
(hint: For more precise location, try *BREAK-ON-SIGNALS*.)
error while parsing arguments to DEFMACRO DOLIST:
bogus sublist
ITEM
to satisfy lambda-list
(SB-DEBUG:VAR LIST &OPTIONAL (SB-IMPL::RESULT NIL))
[Condition of type SB-INT:COMPILED-PROGRAM-ERROR]

Thanks for any help,
-dustin

bradb

unread,
Oct 6, 2006, 2:40:01 PM10/6/06
to
Dustin Withers wrote:
> Hello All,
>
> My first attempt at this hasn't worked and I was hoping for some
> insight. I'm trying to remove all string from a list and return them
> as a list.
>
> This is my first attempt:
> (let ((elements ()))
> (dolist item *LIST*
DOLIST syntax is (dolist (x list) ...)
http://www.lisp.org/HyperSpec/Body/mac_dolist.html

Also, you can use REMOVE to do what you want.

Cheers
Brad

Zach Beane

unread,
Oct 6, 2006, 3:02:55 PM10/6/06
to
"Dustin Withers" <fade...@gmail.com> writes:

> I'm trying to remove all string from a list and return them as a
> list.
>
> This is my first attempt:
> (let ((elements ()))
> (dolist item *LIST*

> (if (stringp item)
> (push (pop *LIST*) elements)
> ()))
> elements)
>
> What is wrong with this?


"bradb" <brad.be...@gmail.com> writes:

> DOLIST syntax is (dolist (x list) ...)
> http://www.lisp.org/HyperSpec/Body/mac_dolist.html

Actually, DOLIST syntax is:

(dolist (var list-form [result-form]) ...)

I use RESULT-FORM a lot. I wouldn't solve the original problem with
dolist, but if I did, it might look something like this:

(let ((elements '()))
(dolist (item *list* elements)
(when (stringp item)
(push item elements))))

Zach

Rahul Jain

unread,
Oct 6, 2006, 3:00:22 PM10/6/06
to
"Dustin Withers" <fade...@gmail.com> writes:

> Hello All,
>
> My first attempt at this hasn't worked and I was hoping for some
> insight. I'm trying to remove all string from a list and return them
> as a list.

Looks like you're trying to use the PARTITION function that some of us
have contributed to.

Um... but it seems to be superseded by SPLIT-SEQUENCE... didn't
PARTITION do something different? Separate the seq into multiple seqs
based on some criterion?

--
Rahul Jain
rj...@nyct.net
Professional Software Developer, Amateur Quantum Mechanicist

Pascal Bourguignon

unread,
Oct 6, 2006, 3:46:38 PM10/6/06
to
"Dustin Withers" <fade...@gmail.com> writes:
> My first attempt at this hasn't worked and I was hoping for some
> insight. I'm trying to remove all string from a list and return them
> as a list.

This is problematic.

There is not list data type in lisp.

We build lists as a pun on cons cells or nil.

(deftype proper-list () (or null (cons t list)))
(deftype list () (or null cons))

The consequence, is that when a variable refers the first cons of a
list, and given that parameter passing is always done by value, not by
reference, we cannot meaningfully remove the first cons of the list
from this list.

Another way to see it is that these chaining of cons cells allow for
sharing of the tail of the lists, and the whole lists can be seen as
their own tail:

(let ((a (list 1 2 3)))
(let ((b a))
;; here, we cannot remove 1 from the list a and have it removed
;; too from the list b!
))


The second case where problems would occur is with empty lists, since
they are all NIL, and you cannot modify NIL. Well for your problem
this wouldn't matter since you can't remove anything from NIL, but
with this conception you couldn't add elements to your list.

So if you really persist in wanting to do what you say you are wanting
to do, then you should create a list data type.

(defstruct mylist elements)

Then you can write:

(defun delete-strings-from-mylist-and-return-them (mylist)
(loop
:for item :in (mylist-elements mylist)
:if (stringp item) :collect item :into strings
:else :collect item :into others
:finally (setf (mylist-elements mylist) others)
(return strings)))

[53]> (defparameter *ml* (make-mylist :elements (list 1 2 "one" "two" 'one 'two)))
*ML*
[54]> (delete-strings-from-mylist-and-return-them *ml*)
("one" "two")
[55]> *ml*
#S(MYLIST :ELEMENTS (1 2 ONE TWO))
[56]>

Note that my implementation doesn't modify the list inside the mylist,
it creates a two lists. This to avoid suprizing results, and to allow
to put a literal list inside a mylist:


[56]> (defparameter *ml* (make-mylist :elements '(1 2 "one" "two" 'one 'two)))
*ML*
[57]> (delete-strings-from-mylist-and-return-them *ml*)
("one" "two")
[58]> *ml*
#S(MYLIST :ELEMENTS (1 2 'ONE 'TWO))
[59]> (defparameter *l* (list 1 2 "one" "two" 'one 'two))
*L*
[60]> (defparameter *ml* (make-mylist :elements *l*))
*ML*
[61]> (delete-strings-from-mylist-and-return-them *ml*)
("one" "two")
[62]> *ml*
#S(MYLIST :ELEMENTS (1 2 ONE TWO))
[63]> *l*
(1 2 "one" "two" ONE TWO)
[64]>

If you use destructive functions (such as POP, DELETE or DELETE-IF)
on the elements of the mylist, then you have to be very careful never
pass literal list (or tails), and to make sure that any other
structure sharing is not done unconciously.

--
__Pascal Bourguignon__ http://www.informatimago.com/
Kitty like plastic.
Confuses for litter box.
Don't leave tarp around.

Geoffrey Summerhayes

unread,
Oct 6, 2006, 3:54:33 PM10/6/06
to

Rahul Jain wrote:
> "Dustin Withers" <fade...@gmail.com> writes:
>
> > Hello All,
> >
> > My first attempt at this hasn't worked and I was hoping for some
> > insight. I'm trying to remove all string from a list and return them
> > as a list.
>
> Looks like you're trying to use the PARTITION function that some of us
> have contributed to.
>
> Um... but it seems to be superseded by SPLIT-SEQUENCE... didn't
> PARTITION do something different? Separate the seq into multiple seqs
> based on some criterion?

I don't believe so, IIRC, SPLIT-SEQUENCE got its name because
enough people argued that the name PARTITION was confusing.

---
Geoff

Dustin Withers

unread,
Oct 6, 2006, 4:11:30 PM10/6/06
to
Wow, cool. Thanks everybody for these great answers.

-dustin

Rahul Jain

unread,
Oct 6, 2006, 4:19:17 PM10/6/06
to
"Geoffrey Summerhayes" <sum...@hotmail.com> writes:

> I don't believe so, IIRC, SPLIT-SEQUENCE got its name because
> enough people argued that the name PARTITION was confusing.

Yes, I do remember that confusion, and thought we decided to have a
PARTITION that would actually perform a partition of a sequence. Oh
well, I guess I was confused. ;)

Dustin Withers

unread,
Oct 6, 2006, 4:24:46 PM10/6/06
to
Pascal,

This is for use with the EDI parser I'm trying to put together. I'm
writing the Lexical Analyzer for the grammar we were talking about in a
different thread.

Here is what I have...(not taking into account what's been stated in
this thread)
(defun parsed-edi-lexer (list)
(let ((lst list))
#'(lambda ()
(if (listp (car lst))
(progn
(setf lst (append (car lst) (cdr lst)))
(if (car lst)
(let ((segment (pop lst)))
(values (intern segment) segment))
(values nil nil)))
(values 'elements (reverse
(let ((elements ()))
(dolist (item lst)
(if (stringp item)
(push (pop lst) elements)))
elements)))))))

This is to be called by a grammar defined using CL-YACC. Any opinions?
;)

-dustin

Lars Rune Nøstdal

unread,
Oct 6, 2006, 5:24:35 PM10/6/06
to

Yeah, I'd use `remove-if' or `delete-if' I think (check the hyperspec for
differences):

cl-user> (remove-if #'stringp '(a b c "hey" 1234 "ho"))
(a b c 1234)
cl-user> (defparameter *list* '(a b c "hey" 1234 "ho"))
*list*
cl-user> (setf *list* (delete-if #'stringp *list*))
(a b c 1234)
cl-user> *list*
(a b c 1234)

--
Lars Rune Nøstdal
http://lars.nostdal.org/

Lars Rune Nøstdal

unread,
Oct 6, 2006, 5:30:31 PM10/6/06
to
On Fri, 06 Oct 2006 11:35:07 -0700, Dustin Withers wrote:

> (if (stringp item)
> (push (pop *LIST*) elements)
> ()))

As a sidenote - it is ok to not supply the else-part of an `if':


cl-user> (let ((items '("string" 'not-a-string)))
(dolist (item items)
(if (stringp item)
(write-line "found a string"))))
found a string
nil

..or to make it more clear that there is no else-part you can use `when':

cl-user> (let ((items '("string" 'not-a-string)))
(dolist (item items)
(when (stringp item)
(write-line "found a string"))))
found a string
nil

0 new messages