Я пытаюсь транспонировать список списков; мои комментарии показывают ход мыслей.
(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))
Что я делаю не так?
Для этого есть простой способ:
(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))