我想映射列表,但要跟踪列表中的元素索引。
在Python中,我可以做一些事情:
map(lambda (idx, elt): "Elt {0}: {1}".format(idx, elt), enumerate(mylist))
我试图将其翻译成以下内容:
(mapcar-something (lambda (elt idx) (format nil "Elt ~D: ~S" idx elt))
'(a b c d))
预期结果:
("Elt 0: A" "Elt 1: B" "Elt 2: C" "Elt 3: D")
但是我找不到我应该使用的mapcar-something功能。我是否需要自己实现(通过循环,也许)?
答案 0 :(得分:8)
CL-USER 25 > (defun iota (n)
(loop for i below n collect i))
IOTA
CL-USER 26 > (iota 4)
(0 1 2 3)
CL-USER 27 > (mapcar (lambda (elt idx)
(format nil "Elt ~D: ~S" idx elt))
'(a b c d)
(iota 4))
("Elt 0: A" "Elt 1: B" "Elt 2: C" "Elt 3: D")
或
CL-USER 28 > (loop for elt in '(a b c d) and idx from 0
collect (format nil "Elt ~D: ~S" idx elt))
("Elt 0: A" "Elt 1: B" "Elt 2: C" "Elt 3: D")
答案 1 :(得分:1)
如果您想要一些看似原始示例的内容:
(defun enumerate (function list)
(let ((idx 0))
(loop for elt in list
collect (funcall function elt idx)
do (incf idx))))
你的例子:
(enumerate (lambda (elt idx) (format nil "Elt ~D: ~S" idx elt))
'(a b c d))
=> ("Elt 0: A" "Elt 1: B" "Elt 2: C" "Elt 3: D")
答案 2 :(得分:0)
Common Lisp的LOOP宏可以自动跟踪索引。
(loop for elt in '(a b c d) and idx from 0
collect (operation-on idx elt))
LOOP自动使用from
初始化的变量增加 1;如果它们是由and
引入的,那么两个赋值(数组的元素和索引)都会立即发生,而不是嵌套。
因此,枚举函数将遵循:
(defun enumerate (list &optional (first-index 0))
(loop for elt in list and idx from first-index
collect (cons idx elt)))
在Common Lisp的表现形式中,按照以下方式定义宏可能是有用的:
(defmacro with-enumerated-list ((list elt idx &key (first-index 0)) &body body)
`(loop for ,elt in ,list and ,idx from ,first-index
collect (progn ,@body)))
在这种情况下,枚举函数可以简化为:
(defun enumerate (list &optional (first-index 0))
(with-enumerated-list (list elt idx :first-index first-index)
(cons idx elt)))
答案 3 :(得分:0)
这是另一个:
(defun enumerate (collection &key (as 'list))
(let ((index -1))
(map as
(lambda (element)
(cons (incf index) element))
collection)))
此代码的优势在于它适用于并且可以生成列表和向量:
CL-USER[2]: (enumerate '(1 2 3))
((0 . 1) (1 . 2) (2 . 3))
CL-USER[3]: (enumerate "abc" :as 'vector)
#((0 . #\a) (1 . #\b) (2 . #\c))