Scheme / Racket:将单个元素追加到列表末尾的最惯用的方法

时间:2016-03-04 06:11:46

标签: functional-programming append scheme lisp racket

我想将元素b附加到列表a(让我们说(a1, a2, ... an)),例如将号码3追加到(1 2)会产生(1 2 3)

到目前为止,我一直在做 (append a (list b)),有点长而不优雅,所以我想知道是否有“更好”的方式...

2 个答案:

答案 0 :(得分:3)

您是否一次性构建一个列表,一个项目?如果是这样,执行此操作的惯用方法是使用cons向后构建列表,然后使用reversing最终结果:

(define (map-using-cons-and-reverse f lst)
  (let loop ((result '())
             (rest lst))
    (if (null? rest)
        (reverse result)
        (loop (cons (f (car rest)) (cdr rest))))))

或者,如果您的列表构建符合“右向折叠”递归方法,那也是惯用的:

(define (map-using-recursion f lst)
  (let recur ((rest lst))
    (if (null? rest)
        '()
        (cons (f (car rest)) (recur (cdr rest))))))

以上代码片段仅用于说明在一般情况下采用的解决方案方法;对于可以使用折叠直接实现的内容,例如map,使用fold更具惯用性:

(define (map-using-cons-and-reverse f lst)
  (reverse (foldl (lambda (item result)
                    (cons (f item) result))
                  '() lst)))

(define (map-using-recursion f lst)
  (foldr (lambda (item result)
           (cons (f item) result))
         '() lst))

答案 1 :(得分:2)

你有多频繁追加到最后?

如果你想要做很多事情(而不是在前面),那么你做错了。正确的方法是翻转事物:认为cons把事情放在后面,first检索最后一个元素,rest检索除了最后的所有内容,等等。然后,你可以使用列表通常

但是,如果你想把事情放在列表的末尾,以便把事情放在前面,那么这是你用一个列表做的最好的事情。你可以编写一个函数来包装你认为“不优雅”的东西。传统上它被称为snoc(向后cons

(define (snoc lst e) (append lst (list e)))

或者如果您更喜欢自己实施整个事情:

(define (snoc lst e)
  (cond
    [(empty? lst) (list e)]
    [(cons? lst) (cons (first lst) (snoc (rest lst) e))]))

请注意,这两种方法具有相同的时间复杂度:O(n)其中n是列表的长度。

但是如果你希望它有效,你可以使用一种称为双端队列的数据结构,这种效率非常高效(每次操作的时间恒定)。有关详细信息,请参阅http://www.westpoint.edu/eecs/SiteAssets/SitePages/Faculty%20Publication%20Documents/Okasaki/jfp95queue.pdf