2010-09-28 11 views
15

Étant donné une liste telle queDécapage éléments en double dans une liste de chaînes dans elisp

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

comment pourrais-je construire une nouvelle liste avec les chaînes en double enlevées, ainsi que les nil s dépouillés, soit

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

L'ordre des éléments doit être préservé - la première occurrence d'une chaîne ne peut pas être supprimée. Les listes que j'ai ici sont courtes, il n'y a donc pas besoin d'utiliser une table de hachage pour la vérification de l'unicité, bien que cela ne nuise certainement pas non plus. Cependant, l'utilisation de la fonctionnalité cl n'est pas une option viable.

Répondre

1

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))) 
+0

Cela fait assez bien l'affaire. J'ai appris sur 'member' maintenant. Y a-t-il aussi une fonction similaire qui permet de spécifier une fonction de comparaison? – rafl

+0

Non, pas que je sache. Cependant, il serait plutôt trivial d'écrire. – Sean

+0

Il y a aussi 'memq' et' memql'. – phils

14

Le Common Lisp package contient de nombreuses fonctions de manipulation de liste, en particulier 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) 

Oui, je me rends compte que vous avez dit que vous ne vouliez pas utiliser cl. Mais je mentionne toujours ceci comme la bonne manière de le faire pour d'autres personnes qui pourraient lire ce fil.

(Pourquoi est-cl pas viable pour vous de toute façon il a été livré avec Emacs pendant environ 20 ans, sans compter moins en vedette des incarnations passées?.)

+0

J'ai fait quelques petits correctifs à Gnus, et dans son journal de commit je vois constamment des changements remplaçant quelque chose de cl par un équivalent non-cl. Je ne suis pas tout à fait sûr de ce que sont les raisons, mais il pourrait très bien être quelque chose entre soutenir les saveurs bizarres ou les versions d'Emacs, ou essayer d'éviter de charger le paquet 'cl' sauf si vraiment nécessaire. – rafl

+2

@rafl Je crois que la restriction contre 'cl' a commencé avec le désir de RMS de garder emacs-lisp petit. Jetez un coup d'œil sur un sujet récent discutant de ce point: http://lists.gnu.org/archive/html/emacs-devel/2010-09/msg01278.html –

+6

@Trey: oh, je vois. Afin de garder le noyau d'Emacs petit, chaque paquet doit réimplémenter ses propres fonctions de structure de données de base. Eh bien, si vous êtes celui qui décide que le noyau d'Emacs contiendra exactement les fonctionnalités que vous utilisez, cela fonctionne. Tout le monde obtient des efforts dupliqués et des ballonnements ... – Gilles

28

Essayez "Sets and Lists" dans le "Lists" section du Emacs Lisp Reference Manual:

(delq nil (delete-dups (list "foo" "bar" nil "moo" "bar" "moo" nil "affe"))) 
+1

Beaucoup plus élégant et direct. Parfois je souhaite vraiment qu'il y ait quelque chose comme des espaces de noms regroupant des fonctions connexes, ou peut-être un schéma de nommage plus cohérent qui permettrait de chercher quelque chose en particulier en devinant son nom: -/ – rafl

+0

Le regroupement (via des conventions de nommage ou des espaces de noms) est difficile il y a toujours plusieurs façons de grouper. Emacs n'essaye pas très fort de le faire, et fournit à la place des choses comme «apropos». Mais ce n'est pas idéal non plus. Nous devrions probablement faire plus d'efforts, il est un peu tard pour corriger la plupart des délinquants. – Stefan

0

Si vous utilisez la bibliothèque dash.el, que vous est tout besoin:

(-distinct (-non-nil '(1 1 nil 2 2 nil 3)) ; => (1 2 3) 

dash.el est écrit par Magnar Sveen et c'est une excellente bibliothèque de manipulation de liste avec de nombreuses fonctions pour toutes sortes de tâches. Je recommande de l'installer si vous écrivez beaucoup de code Elisp. La fonction -distinct supprime les éléments en double d'une liste, -non-nil supprime les éléments nil. Alors que le code ci-dessus est suffisant, je décris ci-dessous une approche alternative, alors n'hésitez pas à ignorer le reste de la publication.

-non-nil a été ajouté dans la version 2.9, donc si pour une raison quelconque, vous devez utiliser les versions antérieures, une autre façon d'obtenir le même est d'utiliser -keep Incorporant en identity fonction, qui retourne juste ce qu'il est donné: (identity 1) ; => 1. L'idée est que -keep ne conserve que les éléments pour lesquels le prédicat renvoie true ("non-nul" dans le jargon Lisp). identity renvoie évidemment non-nul seulement pour toutes les valeurs qui ne sont pas nulles:

(-distinct (-keep 'identity '(1 1 nil 2 2 nil 3)) ; => (1 2 3)