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有一个