Common Lisp中的Python枚举()模拟

时间:2016-05-10 12:59:57

标签: common-lisp

我想映射列表,但要跟踪列表中的元素索引。

在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功能。我是否需要自己实现(通过循环,也许)?

4 个答案:

答案 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))