Transposing lists in Common Lisp

纵饮孤独 提交于 2019-12-17 19:15:56

问题


I am trying to transpose a list of lists; my comments indicate the thought process.

(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? 

But, I really want it to be

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

What am I doing wrong?


回答1:


There is a simple way for this:

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

Your attempt is always returning the original mat. Fix your indentation, and you see that the returned value from the if form is always thrown away.

Edit: How this works:

  • List takes any number of arguments and makes a list of it. Its function definition can be imagined about like this:

    (defun list (&rest arguments)
      arguments) ; exploit the automatic &rest construction
    
  • Mapcar takes a function and any number of lists, and then makes a new list of the values created by calling the function always with one element from those lists. Example: (mapcar #'foo '((A B) (C D))) will construct a new list, where the first element is the result of (foo 'A 'C) and the second the result of (foo 'B 'D).

  • Apply takes a spreadable argument list designator as its last argument. This means that if you give it a list as its last argument, that list can be "spread" to produce individual arguments for the function. Example: (apply #'+ '(1 2 3)) has the same effect as (+ 1 2 3).

Now you can expand the line:

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

=>

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

=>

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

=>

'((A C) (B D))


来源:https://stackoverflow.com/questions/3513128/transposing-lists-in-common-lisp

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!