Самое красивое решение - но без foldr/l
(define (unzip al) (list (map car al) (map cdr al)))
Решение 1 - с foldr
(define (unzip lst)
(foldr (lambda (next-pair acc) (list (cons (car next-pair)
(car acc))
(cons (cdr next-pair)
(cadr acc))))
'(() ())
lst))
Примечание: В foldr
- хотя и не интуитивно - Второй аргумент (и не первый) - это накопленный результат (таким образом теперь переименованный в acc
) - который является первым и вторым списком в списке конечных результатов - и p
следующая пара в списке.Таким образом, первое в списке результатов - (car acc)
, а второе - (cadr acc)
.Я сам неправильно понял это, назвав аргументы функций lambda
p1
и p2
, думая, что foldr
действует на первую и последнюю пару lst
.Таким образом, решая ваш вопрос, я лучше понял, что на самом деле означают два аргумента внутренней lambda
функции foldr
- один - это накопленный результат, а другой - следующий элемент в списке ввода.Однако теперь попробовал foldl
: внутренние аргументы lambda
находятся в том же порядке, что и в foldr
- сначала следующая пара, а затем накопленный результат.
Решение сfoldl
(define (unzip lst)
(foldl (lambda (p acc) (list (append (car acc) (list (car p)))
(append (cadr acc) (list (cdr p)))))
'(() ())
lst))
Несколько более эффективное foldl
решение
(define (unzip lst)
(let ((res (foldl (lambda (p acc) (list (cons (car p) (car acc))
(cons (cdr p) (cadr acc))))
'(() ())
lst)))
(map reverse res)))
Вместо append
, cons
поют результати в конце reverse
формирование получаемых внутренних списков.
Решение 2 - с foldr
Неэффективно, но помогло найти решение 1 (flatten (list x y))
-> (cons x y)
:
(define (unzip lst)
(foldr (lambda (next acc) (list (flatten (list (car next)
(car acc)))
(flatten (list (cdr next)
(cdr acc)))))
'(() ())
lst))
Решение 3 - с foldr
Еще более неэффективно - но помогло добраться до решения 2 (append (list x) (list y))
-> (list x y)
:
(define (unzip lst)
(foldr (lambda (next acc) (list (flatten (append (list (car next))
(list (car acc))))
(flatten (append (list (cdr next)
(cdr acc))))))
'(() ())
lst))
хвостовой рекурсивный раствор без foldr/l
(define (unzip alist)
(define (.unzip l acc) ; even numbered l as a given
(cond ((null? l) (map reverse acc)) ; reverse both inner lists
(else (.unzip (cddr l) (list (cons (car l) (car acc))
(cons (cadr l) (cadr acc)))))))
(.unzip (flatten alist) '(() ())))
Все дают:
> (unzip '((1 . 2) (3 . 4) (5 . 6)))
'((1 3 5) (2 4 6))