2

给定一个数字列表,比如说,如果你有 x -1 = 0 ,你(1 3 6 10 0)如何计算差异 (x i - x i-1 )?

(本例中的结果应该是(1 2 3 4 -10)

我发现这个解决方案是正确的:

(定义(pairwise-2 f init l)
  (第一的
   (折叠
    (λ (x acc-data)
      (let ([result-list (first acc-data)]
            [prev-x (第二个 acc-data)])
        (列表
         (追加结果列表 (list(fx prev-x)))
         X)))
    (列表空 0)
    l)))

(pairwise-2 - 0 '(1 3 6 10 0))
;; => (1 2 3 4 -10)

但是,我认为应该有更优雅但同样灵活的解决方案。这只是丑陋的。

我是函数式编程的新手,想听听有关代码的任何建议。

谢谢。

4

7 回答 7

2

map接受多个参数。所以我会做

(define (butlast l)
  (reverse (cdr (reverse l))))
(let ((l '(0 1 3 6 10)))
  (map - l (cons 0 (butlast l)))

如果您想将其包装在一个函数中,请说

(define (pairwise-call f init l)
  (map f l (cons init (butlast l))))

这当然不是Little Schemer Way,而是避免自己编写递归的方式。选择您最喜欢的方式。

于 2009-03-13T14:36:40.137 回答
1

Haskell 告诉我使用zip;)

(define (zip-with f xs ys)
  (cond ((or (null? xs) (null? ys)) null)
        (else (cons (f (car xs) (car ys))
                    (zip-with f (cdr xs) (cdr ys))))))
(define (pairwise-diff lst) (zip-with - (cdr lst) lst))

(pairwise-diff (list 1 3 6 10 0))
; gives (2 3 4 -10)
于 2009-03-13T14:51:27.713 回答
1

无论如何,只要最短的参数列表用完,映射就不会完成吗?

(define (pairwise-call fun init-element lst)
  (map fun lst (cons init-element lst)))

编辑:jleedev 告诉我,至少在一个方案实施中情况并非如此。这有点烦人,因为没有 O(1) 操作来切断列表的末尾。

也许我们可以使用reduce

(define (pairwise-call fun init-element lst)
  (反向 (cdr (减少 (lambda (ab)
                          (追加 (列表 b (- b (car a))) (cdr a)))
                        (缺点 (list init-element) lst)))))

(免责声明:快速破解,未经测试)

于 2009-03-13T14:53:46.180 回答
1

在改进和适应 PLT Scheme plinth代码之后,我认为近乎完美的解决方案是:

(定义(成对应用 f l0 l)
  (如果(空?l)
      '()
      (让 ([l1 (第一个 l)])
        (cons (f l1 l0) (成对应用 f l1 (rest l))))))
于 2009-03-12T15:49:01.047 回答
1

多年来我没有做过计划,但这让我觉得这是一个典型的小 lisper 类型问题。

我从一个基本定义开始(请忽略括号的错位 - 我没有方便的 Scheme 解释器:

(define pairwise-diff
    (lambda (list)
      (cond
       ((null? list) '())
       ((atom? list) list)
       (t (pairwise-helper 0 list)))))

这处理 null 和 atom 的废话,然后将肉类案例委托给助手:

(define pairwise-helper
    (lambda (n list)
       (cond
         ((null? list) '())
         (t
            (let ([one (car list)])
               (cons (- one n) (pairwise-helper one (cdr list))))
         ))))

您可以使用“if”重写它,但我硬连线使用 cond。

这里有两种情况:空列表 - 这很容易,其他一切。对于其他一切,我抓住列表的头部并将这个差异用于递归案例。我不认为它变得更简单。

于 2009-03-12T15:12:25.453 回答
0

这是最简单的方法:

(define (solution ls)
  (let loop ((ls (cons 0 ls)))
    (let ((x (cadr ls)) (x_1 (car ls)))
      (if (null? (cddr ls)) (list (- x x_1))
          (cons (- x x_1) (loop (cdr ls)))))))

(display (equal? (solution '(1)) '(1))) (newline)
(display (equal? (solution '(1 5)) '(1 4))) (newline)
(display (equal? (solution '(1 3 6 10 0)) '(1 2 3 4 -10))) (newline)

写出每个示例的代码扩展,看看它是如何工作的。

如果您有兴趣开始使用 FP,请务必查看如何设计程序。当然,它是为刚接触编程的人编写的,但其中包含大量好的 FP 习语。

于 2009-03-27T18:36:27.490 回答
0
(define (f l res cur)
  (if (null? l)
    res
    (let ((next (car l)))
      (f (cdr l) (cons (- next cur) res) next))))

(define (do-work l)
  (reverse (f l '() 0)))

(do-work '(1 3 6 10 0))

==> (1 2 3 4 -10)
于 2009-04-06T12:43:48.263 回答