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)?
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")
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)))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With