2010-08-18 75 views
10

我想轉置列表的列表;我的評論表明了思維過程。在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? 

但是,我真的希望它是

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

我在做什麼錯?

+0

這被稱爲[矩陣轉置](http://en.wikipedia.org/wiki/Transpose)。 – sds 2013-08-27 18:43:52

+0

@sds:... yuuup。爲什麼我3年前沒有看到超越我。給我幾分鐘,我會解決這個問題。 – 2013-08-27 22:38:33

回答

23

有這個一個簡單的方法:

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

你嘗試總是返回原來的mat。修復縮進,並且您看到從if表單返回的值總是被丟棄。

編輯:這是如何工作:

  • List接受任何數量的參數,並使得它的一個列表。它的功能定義可想而知大約是這樣的:

    (defun list (&rest arguments) 
        arguments) ; exploit the automatic &rest construction 
    
  • Mapcar接受一個函數和任意數量的名單,然後讓創造的價值的 新名單與那些 一個元素總是調用該函數名單。示例:(mapcar #'foo '((A B) (C D)))將構造一個新列表,其中第一個元素是 結果(foo 'A 'C),第二個結果是(foo 'B 'D)

  • Apply需要一個可擴展參數列表標誌作爲其最後的 參數。這意味着如果你給它一個列表作爲它的最後一個參數 ,那麼這個列表可以被「擴展」來產生函數的單個參數 。例如:(apply #'+ '(1 2 3))(+ 1 2 3)具有相同的 效果。

現在,您可以展開行:

(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。你能否闡明一些關於旋轉的推理?我不太清楚*它如何生成解決方案。 – 2010-08-18 14:51:20

+0

某些退化病例存在問題。嘗試'(旋轉零)'或'(旋轉'(零))' – 2017-02-08 21:23:21