Транспонирование списков в 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))

Что я делаю не так?

11
задан Paul Nathan 27 August 2013 в 22:40
поделиться

1 ответ

Для этого есть простой способ:

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

Ваша попытка всегда возвращает исходный мат . Исправьте отступ, и вы увидите, что возвращаемое значение из формы if всегда отбрасывается.

Изменить: Как это работает:

  • Список принимает любое количество аргументов и составляет их список.Его определение функции можно представить примерно так:

     (defun list (& rest arguments)
    аргументы); использовать конструкцию автоматики и отдыха
    
  • Mapcar принимает функцию и любое количество списков, а затем создает новый список значений, созданный путем вызова функции всегда с один элемент из этих списков. Пример: (mapcar # 'foo' ((A B) (C D))) создаст новый список, где первым элементом будет результат (foo 'A' C) , а второй результат (foo 'B' D) .

  • 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))
25
ответ дан 3 December 2019 в 04:12
поделиться