2010-09-28 19 views
15

otrzymali listę takich jakodizolowania duplikatów elementów na liście ciągów w Elisp

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

jak bym zbudować nową listę z podwójnych strun usunięte, jak również nil s usuwane, tj

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

Kolejność elementów musi być zachowana - pierwsze wystąpienie ciągu znaków nie może zostać usunięte.

Lista, z którą mam do czynienia, jest krótka, więc nie ma potrzeby używania czegoś w rodzaju tabeli haszów do sprawdzania unikalności, chociaż z pewnością nie zaszkodzi. Jednak korzystanie z funkcji cl nie jest realną opcją.

Odpowiedz

1

Tu 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

To całkiem fajnie. Dowiedziałem się już o "członku". Czy istnieje również podobna funkcja, która pozwala na określenie funkcji porównania? – rafl

+0

Nie, nie o tym wiem. Jednak pisanie byłoby dość trywialne. – Sean

+0

Istnieje również 'memq' i' memql'. – phils

14

Common Lisp package zawiera wiele funkcji lista manipulacji, w szczególności 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) 

Tak, zdaję sobie sprawę, mówiłeś, że nie chcesz używać cl. Nadal jednak wspominam o tym, jako o właściwej drodze dla innych osób, które mogą czytać ten wątek.

(Dlaczego cl nie opłacalne dla Ciebie i tak To zostało wysłane z Emacs przez około 20 lat, nie licząc mniej polecanych przeszłych wcieleń?).

+0

Zrobiłem kilka małych poprawek do Gnusa, aw jego dzienniku zatwierdzenia ciągle widzę zmiany zastępujące coś z cl z nie-cl odpowiednikiem. Nie jestem do końca pewien, jakie są tego powody, ale może to być coś pomiędzy wspieraniu dziwnych smaków Emacsa lub wersjami, lub próbą uniknięcia ładowania pakietu 'cl', chyba że jest to naprawdę konieczne. – rafl

+2

@rafl Uważam, że ograniczenie w stosunku do "cl" rozpoczęło się od chęci programu RMS do utrzymania małego poziomu emacs-lizp. Sprawdź ostatni wątek omawiający ten punkt: http://lists.gnu.org/archive/html/emacs-devel/2010-09/msg01278.html –

+6

@Trey: oh, widzę. Aby utrzymać rdzeń Emacsa w niewielkim stopniu, wymagaj od każdego pakietu ponownego zastosowania własnych podstawowych funkcji struktur danych. Cóż, jeśli jesteś osobą, która decyduje, że rdzeń Emacsa będzie zawierał dokładnie te funkcje, to działa. Wszyscy inni dostają powielony wysiłek i rozdęcie się ... – Gilles

28

Spróbuj "Sets and Lists" w "Lists" section z Emacs Lisp Reference Manual:

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

Znacznie bardziej elegancko i prosto. Czasem naprawdę chciałbym, aby istniało coś podobnego do przestrzeni nazw grupujących powiązane funkcje, lub może bardziej spójny schemat nazewnictwa, który pozwoliłby znaleźć coś szczególnego poprzez odgadnięcie jego nazwy: -/ – rafl

+0

Grupowanie (poprzez konwencje nazewnictwa lub przestrzenie nazw) jest trudne, ponieważ zawsze istnieje wiele sposobów na grupowanie. Emacs nie próbuje bardzo ciężko to zrobić, a zamiast tego zapewnia rzeczy typu 'apropos'. Ale to też nie jest idealne. Najprawdopodobniej powinniśmy się bardziej postarać, choć trochę za późno, by naprawić większość sprawców. – Stefan

0

Jeśli używasz dash.el bibliotekę, to wszystko, czego potrzebujesz:

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

dash.el jest napisany przez Magnara Sveena i jest świetną biblioteką do manipulowania listami z wieloma funkcjami do różnych zadań. Zalecam zainstalowanie go, jeśli piszesz dużo kodu Elisp. Funkcja -distinct usuwa powielone elementy z listy, -non-nil usuwa elementy nil. Chociaż powyższy kod jest wystarczający, poniżej opisuję alternatywne podejście, więc nie wahaj się zignorować reszty postu.

-non-nil został dodany w wersji 2.9, więc jeśli z jakiegoś powodu trzeba używać starszych wersji, inny sposób na osiągnięcie samo jest użycie -keep z wbudowanym identity funkcji, która właśnie wraca cokolwiek to jest podane: (identity 1) ; => 1. Chodzi o to, że -keep przechowuje tylko te elementy, dla których predykat zwraca true ("non-nil" w żargonie Lispa). identity oczywiście zwraca wartość zerową tylko dla wartości, które nie są zerowe:

(-distinct (-keep 'identity '(1 1 nil 2 2 nil 3)) ; => (1 2 3) 
Powiązane problemy