首页 > 解决方案 > 是否有内置的 Racket 可以将一个元素作为列表重复 n 次?

问题描述

我意识到这对我自己来说是微不足道的,但我很好奇 Racket 是否具有与 Python 中以下内容等效的内置函数或语法:

>>> n = 5
>>> element = "arbitrary string"
>>> [element] * n
['arbitrary string', 'arbitrary string', 'arbitrary string', 'arbitrary string', 'arbitrary string']

如果不是,那么在 Racket 中做这种事情的惯用方式是什么?现在我在 Racket 中执行上述操作的方式是:


(let ((n 5)
      (element "arbitrary string"))
  (map (λ (x) element)
       (range n)))

任何建议都非常感谢,谢谢!

标签: schemelispracket

解决方案


Python["arbitrary string"] * 5可以(make-list 5 "arbitrary string")在 Racket 中翻译。

但是,这通常不是您想要的,因为元素是共享的。这对于不可变值来说完全没问题,但对于可变值,它可能会产生不良后果:

在 Python 中

>>> xs = [[]] * 5
>>> xs[0].append(1)
>>> xs
[[1], [1], [1], [1], [1]]

在球拍中:

> (define xs (make-list 5 (box 0)))
> (set-box! (first xs) 1)
> xs
'(#&1 #&1 #&1 #&1 #&1)

在 Python 中,您可以使用列表推导来避免该问题:

>>> xs = [[] for x in range(5)]
>>> xs[0].append(1)
>>> xs
[[1], [], [], [], []]

在 Racket 中,您可以使用build-list.

> (define xs (build-list 5 (thunk* (box 0))))
> (set-box! (first xs) 1)
> xs
'(#&1 #&0 #&0 #&0 #&0)

以下是也可以避免该问题的方法:

(build-list 5 (thunk* (box 0)))
(for/list ([x (in-range 5)]) (box 0))

(for/list ([x (range 5)]) (box 0))
(map (thunk* (box 0)) (range 5))

最后两个不推荐,因为它需要先创建列表(range 5),效率低(类似于Python的["hello" for x in list(range(5))])。

请注意,这(thunk* v)相当于(lambda (ignored...) v),这就是您获得“新鲜”的原因v,避免了元素共享问题。但是,如果您有意共享元素,也可以使用(const v)代替(thunk* v).

> (define xs (build-list 5 (const (box 0))))
> (set-box! (first xs) 1)
> xs
'(#&1 #&1 #&1 #&1 #&1)

最后,build-list实际上也为您提供了索引。我thunk*以前使用过,因为对于您的问题,我们不需要索引。但是,如果您需要它,您可以使用它:

> (build-list 5 (lambda (x) (* 2 x)))
'(0 2 4 6 8)

推荐阅读