最漂亮的解决方案 - 但没有 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 的第一对和最后一对。因此,通过解决您的问题,我更好地理解了foldr 的内部lambda 函数中的两个参数的实际含义——一个是累积结果,另一个是输入列表中的下一个元素。但是,现在尝试了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,conssing 结果和最后reverseing 结果内部列表。
解决方案 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))