Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python enumerate() analog in Common Lisp

Tags:

common-lisp

I want to map over a list, but keeping track of the element index in the list.

In Python I can do something along the lines of:

map(lambda (idx, elt): "Elt {0}: {1}".format(idx, elt), enumerate(mylist))

I was trying to translate it to something along the lines of:

(mapcar-something (lambda (elt idx) (format nil "Elt ~D: ~S" idx elt))
                  '(a b c d))

Expected result:

("Elt 0: A" "Elt 1: B" "Elt 2: C" "Elt 3: D")

But I can't find the mapcar-something function that I should use. Do I need to implement that myself (via loop, maybe)?

like image 396
ssice Avatar asked May 10 '16 12:05

ssice


2 Answers

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")

or

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")
like image 187
Rainer Joswig Avatar answered Sep 28 '22 07:09

Rainer Joswig


Common Lisp's LOOP macro can automatically keep track of the index.

(loop for elt in '(a b c d) and idx from 0
      collect (operation-on idx elt))

LOOP automatically increases by 1 a variable initialized with from; and if they are introduced by and then both assignations (the element of the array and the index) happen at once, not nested.

Thus, an enumerate function would be along the lines of:

(defun enumerate (list &optional (first-index 0))
  (loop for elt in list and idx from first-index
    collect (cons idx elt)))

In the expressiveness of Common Lisp, it would possibly be useful to define a macro along the lines of:

(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)))

In which case, the enumerate function could be reduced to:

(defun enumerate (list &optional (first-index 0))
  (with-enumerated-list (list elt idx :first-index first-index)
    (cons idx elt)))
like image 36
ssice Avatar answered Sep 28 '22 08:09

ssice