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

Functional programming Scheme/Racket:将单个元素附加到列表末尾的最惯用方法,functional-programming,append,scheme,lisp,racket,Functional Programming,Append,Scheme,Lisp,Racket,我想将元素b附加到列表a(比方说(a1,a2,…an)),例如,将数字3附加到(12)会给出(13) 到目前为止我一直在做 (附加a(列表b)),这有点长而且不雅观,所以我想知道是否有一种“更好”的方法…你需要多长时间附加到末尾 如果你想做很多事情(而不是站在前面),那么你就做错了。正确的方法是翻转:认为cons将内容放在后面,首先检索最后一个元素,rest检索除最后一个之外的所有内容,等等。然后,您可以正常使用列表 然而,如果你想把事情放在列表的末尾,就像把事情放在前面一样频繁,那么这是你能用

我想将元素
b
附加到列表
a
(比方说
(a1,a2,…an)
),例如,将数字
3
附加到
(12)
会给出
(13)

到目前为止我一直在做
(附加a(列表b))
,这有点长而且不雅观,所以我想知道是否有一种“更好”的方法…

你需要多长时间附加到末尾

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

然而,如果你想把事情放在列表的末尾,就像把事情放在前面一样频繁,那么这是你能用一个列表做的最好的事情。你可以写一个功能来包装你认为“不雅”的东西。传统上称为
snoc
(向后
cons

或者,如果您更愿意自己实施整个过程:

(define (snoc lst e)
  (cond
    [(empty? lst) (list e)]
    [(cons? lst) (cons (first lst) (snoc (rest lst) e))]))
请注意,这两种方法具有相同的时间复杂性:
O(n)
其中
n
是列表的长度


但如果您希望它高效,可以使用一种称为双端队列的数据结构,它非常高效(每次操作的时间恒定)。有关更多详细信息,请参阅。

您是否在逐段构建列表,一次创建一个项目?如果是这样,惯用的方法是使用
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))))))
(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))

以上代码片段仅用于说明在一般情况下应采取的解决方法;对于可以使用fold直接实现的事情,如
map
,使用fold更为惯用:

(define (map-using-recursion f lst)
  (let recur ((rest lst))
    (if (null? rest)
        '()
        (cons (f (car rest)) (recur (cdr rest))))))
(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))

我认为
(附加a(列表b))
是最惯用的方法。这是O(n),但不幸的是,在处理单链接列表时,没有比这更好的了。如果你做了大量的追加,你可能需要一个不同的数据结构来更优雅地处理追加。你说的
(追加a(列表b))
是什么意思?语法很长,或者实际的过程效率很低,或者什么的?不完全是这样。(1) 队列能够将物品放在一边,并从另一边检索物品。(2) 列表(或堆栈)能够把东西放在一边,从同一边检索东西(3)deque能够把东西放在任何一边,从任何一边检索东西。我链接到的R6RS源实现了一个队列,我想这就是本文中描述的。它有一个输入列表和一个输出列表,其中队列和出队列为O(1),除非输出列表为空,其中包括一个与输入列表相反的值,以成为输出列表(O(n))。它也可以很容易地作为一个deque工作,因为您只需在out列表的顶部添加新元素O(1)更新事实上,同一个repo有一个