tags:

views:

79

answers:

3

Given a list such as

(list "foo" "bar" nil "moo" "bar" "moo" nil "affe")

how would I build a new list with the duplicate strings removed, as well as the nils stripped, i.e.

(list "foo" "bar" "moo" "affe")

The order of the elements needs to be preserved - the first occurence of a string may not be removed.

The lists I'm dealing with here are short, so there's no need to use anything like a hash table for the uniqueness check, although doing so certainly wouldn't hurt either. However, using cl functionality is not a viable option.

+2  A: 

Here ya go:

(defun strip-duplicates (list)
  (let ((new-list nil))
    (while list
      (when (and (car list) (not (member (car list) new-list)))
        (setq new-list (cons (car list) new-list)))
      (setq list (cdr list)))
    (nreverse new-list)))
Sean
This does the trick quite nicely. I've learned about `member` now. Is there also a similar function that allows specifying a comparison function?
rafl
No, not that I know of. It would be pretty trivial to write, though.
Sean
There's also `memq` and `memql`.
phils
+3  A: 

The Common Lisp package contains many list manipulation functions, in particular remove-duplicates.

(require 'cl)
(remove-duplicates (list "foo" "bar" nil "moo" "bar" "moo" nil "affe")
                   :test (lambda (x y) (or (null y) (equal x y)))
                   :from-end t)

Yes, I realize you said you didn't want to use cl. But I'm still mentioning this as the right way to do it for other people who might read this thread.

(Why is cl not viable for you anyway? It's been shipped with Emacs for about 20 years now, not counting less featured past incarnations.)

Gilles
I've been doing a couple of tiny patches to Gnus, and in its commit log I constantly see changes replacing something from cl with a non-cl equivalent. I'm not quite sure what the reasons are exactly, but it might very well be something between supporting weird Emacs flavours or versions, or trying to avoid loading the `cl` package unless really necessary.
rafl
@rafl I believe the restriction against `cl` started from RMS' desire to keep emacs-lisp small. Check out a recent thread discussing this point: http://lists.gnu.org/archive/html/emacs-devel/2010-09/msg01278.html
Trey Jackson
@Trey: oh, I see. In order to keep the core of Emacs small, require every package to reimplement their own basic data structures functions. Well, if you're the one who decides that the core of Emacs will contain exactly the features you use, it works. Everyone else gets duplicated effort and bloat...
Gilles
+3  A: 

Try the "Lists" section of the Emacs Lisp Reference Manual:

(delq nil (delete-dups (list "foo" "bar" nil "moo" "bar" "moo" nil "affe")))
scottfrazer
Much more elegant and straight-forward. Somtimes i really wish there was something like namespaces grouping related functions together, or maybe a more consistent naming scheme that'd allow looking for something in particular by guessing it's name :-/
rafl