2010-01-18 16 views
10

Sto provando a scrivere una funzione Common Lisp che mi fornirà tutte le possibili permutazioni di una lista, usando ogni elemento una sola volta. Ad esempio, l'elenco '(1 2 3) fornirà l'output ((1 2 3) (1 3 2) (2 1 3) (2 3 1) (3 1 2) (3 2 1)).Come posso ottenere tutte le possibili permutazioni di una lista con Common Lisp?

Ho già scritto qualcosa che funziona, ma è goffo, non sempre funziona e non lo capisco nemmeno veramente. Non sto chiedendo il codice, solo forse per qualche consiglio su come pensarci. Non so molto sulla scrittura degli algoritmi.

Grazie, Jason

+1

di solito è una buona idea postare il codice che hai scritto finora. In questo modo possiamo vedere in che modo stai pensando ... –

+0

Se questo è compito, taggalo come tale. –

+1

Questo non è compito. Ho volutamente omesso il codice che ho finora. Non voglio contaminare le risposte con la mia idea sbagliata. – Jason

risposta

-2

non sono sicuro se la tua domanda è di circa Common Lisp, o circa l'algoritmo.

Ci sono problemi simili (e soluzioni) per altre lingue qui, ad es. Python. Python può spesso essere tradotto in Common Lisp virtualmente line-for-line, quindi sceglierne uno e portarlo? :-)

14

Come un approccio di base, "tutte le permutazioni" seguono questo schema ricorsivo:

 
    all permutations of a list L is: 
    for each element E in L: 
     that element prepended to all permutations of [ L with E removed ] 

Se prendiamo come dato di non avere elementi duplicati nel proprio elenco, il seguente dovrebbe fare:

 
(defun all-permutations (list) 
    (cond ((null list) nil) 
     ((null (cdr list)) (list list)) 
     (t (loop for element in list 
      append (mapcar (lambda (l) (cons element l)) 
          (all-permutations (remove element list))))))) 
+0

Grazie! Questo è un po 'come quello che ho avuto, ma con alcune piccole e importanti differenze. L'unico problema che vedo con questo è che (tutte le permutazioni '(1 2 3)) e (tutte le permutazioni' (1 1 2 3)) danno lo stesso risultato, ma dovrebbe essere abbastanza facile da cambiare. (Il mio obiettivo ultimo qui è quello di mescolare le parole.) – Jason

+0

Se hai elementi indistinguibili, diventa un po 'più complicato, dovrai eseguire qualche pre-elaborazione per evitare di generare "la stessa" permutazione più di una volta. Tuttavia, invece di usare una lista come sopra, usando un vettore di (SYMBOL. COUNT) come la struttura dati che si passa e il conteggio decrementale (su una copia!) Invece di eliminare dovrebbe occuparsi anche di questo. – Vatine

+0

(permutazioni defun() (etichette ((vedere-permutazioni (articoli) (se gli articoli (mapcan (lambda (x) (mapcar (lambda (y) (cons xy)) (vedere-permutazioni (rimuovono x articoli)))) articoli) '(())))) (do-permutations' ("Guy" "Man" "Amico")))) –

3

Passeggiata nell'elenco, selezionando ogni elemento a turno. Quell'elemento sarà il primo elemento della tua permutazione corrente.

Contro questo elemento per tutte le permutazioni degli elementi rimanenti.

8

Ecco la risposta che consente elementi ripetuti. Il codice è ancora più "lispish" in quanto non utilizza loop, con lo svantaggio di essere meno comprensibili soluzione di Rainer Joswig:

(defun all-permutations (lst &optional (remain lst)) 
    (cond ((null remain) nil) 
     ((null (rest lst)) (list lst)) 
     (t (append 
      (mapcar (lambda (l) (cons (first lst) l)) 
        (all-permutations (rest lst))) 
      (all-permutations (append (rest lst) (list (first lst))) (rest remain)))))) 

l'opzionale rimangono argomento è usato per cdring l'elenco, ruotando la lista elementi prima di entrare nella ricorsione.

+0

potrebbe eseguire il wrapping del cond in remove-duplicates se le permutazioni univoche necessario – mcheema

Problemi correlati