2010-08-18 33 views
10

Estoy tratando de transponer una lista de listas; mis comentarios indican el proceso de pensamiento.Transposición de listas en Common Lisp

(setq thingie '((1 2 3) (4 5 6) (7 8 9))) ;;test case 

(defun trans (mat) 
    (if (car mat) 
    (let ((top (mapcar 'car mat)) ;;slice the first row off as a list 
      (bottom (mapcar 'cdr mat))) ;;take the rest of the rows 
     (cons top (trans bottom)))) ;;cons the first-row-list with the next-row-list 
    mat) 

(trans thingie) 
=> ((1 2 3) (4 5 6) (7 8 9))   ;;wait what? 

Pero, realmente quieren que sea

((1 4 7) (2 5 8) (3 6 9)) 

¿Qué estoy haciendo mal?

+0

Esto se llama [matriz transpuesta] (http://en.wikipedia.org/wiki/Transpose). – sds

+0

@sds: ... yuuup. Por qué no lo vi hace 3 años me supera. Dame unos minutos y arreglaré esto. –

Respuesta

23

No es una manera simple para esto:

(defun rotate (list-of-lists) 
    (apply #'mapcar #'list list-of-lists)) 

Su intento es siempre devolverá el original mat. Corrija su sangría y verá que el valor devuelto del formulario if siempre se descarta.

Editar: cómo funciona esto:

  • List toma cualquier número de argumentos y hace una lista de la misma. Su definición de la función se puede imaginar más o menos así:

    (defun list (&rest arguments) 
        arguments) ; exploit the automatic &rest construction 
    
  • Mapcar toma una función y cualquier número de listas, y luego hace una nueva lista de los valores creados llamando a la función siempre con un elemento de aquellos liza. Ejemplo: (mapcar #'foo '((A B) (C D))) construirá una nueva lista, donde el primer elemento es el resultado de (foo 'A 'C) y el segundo el resultado de (foo 'B 'D).

  • Apply toma un designador de lista de argumentos extensible como su último argumento . Esto significa que si le da una lista como su último argumento , esa lista puede "separarse" para producir argumentos individuales para la función. Ejemplo: (apply #'+ '(1 2 3)) tiene el mismo efecto como (+ 1 2 3).

Ahora se puede ampliar la línea:

(apply #'mapcar #'list '((A B) (C D))) 

=>

(mapcar #'list '(A B) '(C D)) 

=>

(list (list 'A 'C) (list 'B 'D)) 

=>

'((A C) (B D)) 
+0

Hnnng. ¿Puedes elucidar un poco más sobre el razonamiento para tu rotación? No veo exactamente * cómo * genera la solución. –

+0

Hay un problema con algunos casos degenerados. Pruebe '(rotar nil)' o '(rotar '(nil))' –