这是使用Scheme编码的unzip
函数的代码
(define (unzip lst)
(define (firsts lst)
(if (null? lst)
'()
(cons (caar lst)
(firsts (cdr lst)))))
(define (seconds lst)
(if (null? lst)
'()
(cons (cdar lst)
(seconds (cdr lst)))))
(list (firsts lst) (seconds lst)))
将给我们这样的输出:
(unzip '((1 . 2) (3 . 4) (5 . 6))) => '((1 3 5) (2 4 6))'
但是我很好奇我如何使用Scheme unzip
函数来实现相同的函数foldr
,有人可以提供帮助吗?真的非常感谢。
答案 0 :(得分:0)
由于您使用了racket
标签,因此我将使用for/fold
给出答案,该语法比foldr
或foldl
更好。 1 < / sup>
for/fold
的语法大致为:
(for/fold <accumulators>
<iterators>
<body>)
我们可以使用两个累加器ret1
和ret2
来存储两个列表中的每一个,然后以累加器#:result
的形式将它们放在一起:
([ret1 '()]
[ret2 '()]
#:result (list (reverse ret1) (reverse ret2)))
迭代器非常简单:
([i (in-list lst)])
最后,身体只需将每一对分开,然后将其附加到蓄电池上即可。
(values (cons (car i) ret1)
(cons (cdr i) ret2))
因此,将它们放在一起可以得到:
(define (unzip lst)
(for/fold ([ret1 '()]
[ret2 '()]
#:result (list (reverse ret1) (reverse ret2)))
([i (in-list lst)])
(values (cons (car i) ret1)
(cons (cdr i) ret2))))
符合预期:
> (unzip '((1 . 2) (3 . 4) (5 . 6)))
'((1 3 5) (2 4 6))
1 至少在我看来,这些东西总是有点主观的。
答案 1 :(得分:0)
最精美的解决方案-但没有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
)-这是a中的第一和第二个列表最终结果的列表-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))
答案 2 :(得分:0)
这个简单的实现不使用fold
*,map
,reverse
,flatten
或append
,而是使用尾部调用>
(define (unzip xs (return list))
(if (empty? xs)
(return empty empty)
(unzip (cdr xs)
(lambda (l r)
(return (cons (caar xs) l)
(cons (cdar xs) r))))))
(unzip '((1 . 2) (3 . 4) (5 . 6)))
;; '((1 3 5) (2 4 6))
答案 3 :(得分:0)
在Leif的答案的基础上,Racket提供了更多类似for/fold
的形式来为您处理累积的某些部分。例如:
#lang racket
(define (unzip lst)
(define-values (firsts seconds)
(for/lists (firsts seconds)
([pr (in-list lst)])
(values (car pr) (cdr pr))))
(list firsts seconds))
(unzip '((1 . 2) (3 . 4) (5 . 6)))