如何在方案中使用文件夹写解压缩?

时间:2018-10-20 01:44:16

标签: recursion functional-programming scheme racket

这是使用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,有人可以提供帮助吗?真的非常感谢。

4 个答案:

答案 0 :(得分:0)

由于您使用了racket标签,因此我将使用for/fold给出答案,该语法比foldrfoldl更好。 1 < / sup>

for/fold的语法大致为:

(for/fold <accumulators>
          <iterators>
  <body>)

我们可以使用两个累加器ret1ret2来存储两个列表中的每一个,然后以累加器#: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函数p1p2的参数,认为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 *,mapreverseflattenappend,而是使用尾部调用

(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)))