Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Mapcar: how can I pass the list index to the function?

1,095 views
Skip to first unread message

Brian Houser

unread,
Feb 5, 2012, 4:56:57 PM2/5/12
to
Hi comp.lang.lisp,

I'm relatively new to common lisp, so forgive me if this should be
obvious: Is it possible to pass the list index to the function using
mapcar? For example:

> (mapcar #'(lambda (x index) (if (oddp index) T NIL)) '(1 2 3 4))
(NIL T NIL T)

Thanks!
Brian

Mirko Vukovic

unread,
Feb 5, 2012, 5:20:58 PM2/5/12
to
No, but you can generate the index on the fly using closures:

(let ((index 0))
(mapcar #'(lambda (arg)
(format t "~a: ~a~%" index arg)
(incf index))
(list 'a 'b 'c 'd)))

HTH,

Mirko

Brian Houser

unread,
Feb 5, 2012, 6:14:52 PM2/5/12
to
This makes a lot of sense and really helps. Thanks!
Brian

Joseph Taylor

unread,
Feb 5, 2012, 6:04:24 PM2/5/12
to
Here's my try at it:

(defun mapcar-with-index (function list &rest more-lists)
(let ((index -1))
(apply #'mapcar (lambda (&rest args)
(incf index)
(apply function (append args (list index))))
(append (list list) more-lists))))

; CL-USER> (mapcar-with-index #'list (list 1 2 3 4 5))
; ((1 0) (2 1) (3 2) (4 3) (5 4))

Bear in mind that I too am a beginner with this language.

Joe

Brian Houser

unread,
Feb 5, 2012, 7:52:18 PM2/5/12
to
> Here's my try at it:
>
> (defun mapcar-with-index (function list &rest more-lists)
>   (let ((index -1))
>     (apply #'mapcar (lambda (&rest args)
>                       (incf index)
>                       (apply function (append args (list index))))
>            (append (list list) more-lists))))
>
> ; CL-USER> (mapcar-with-index #'list (list 1 2 3 4 5))
> ; ((1 0) (2 1) (3 2) (4 3) (5 4))
>
> Bear in mind that I too am a beginner with this language.
>
> Joe

Ooh, very nice. I was thinking of eventually defining my own version
of mapcar that tracks the index, but you've beat me to the punch.

Brian

Joseph Taylor

unread,
Feb 6, 2012, 10:57:17 AM2/6/12
to
On Feb 5, 4:52 pm, Brian Houser <brianlhou...@gmail.com> wrote:
> Ooh, very nice.  I was thinking of eventually defining my own version
> of mapcar that tracks the index, but you've beat me to the punch.
>
> Brian

Here's another approach:

(loop for index from 0
and value in '(1 2 3 4 5)
collecting (list value index))

; ((1 0) (2 1) (3 2) (4 3) (5 4))

Joe

Marco Antoniotti

unread,
Feb 6, 2012, 12:11:49 PM2/6/12
to
On Monday, February 6, 2012 4:57:17 PM UTC+1, Joseph Taylor wrote:
> On Feb 5, 4:52 pm, Brian Houser
> wrote:
> > Ooh, very nice.  I was thinking of eventually defining my own version
> > of mapcar that tracks the index, but you've beat me to the punch.
> >
> > Brian
>
> Here's another approach:
>
> (loop for index from 0
> and value in '(1 2 3 4 5)
> collecting (list value index))
>
> ; ((1 0) (2 1) (3 2) (4 3) (5 4))
>
> Joe

(mapcar 'list values (iota (length values)))

Where IOTA is left as simple exercise for the reader :)

Cheers

MA

Kaz Kylheku

unread,
Feb 7, 2012, 1:16:45 AM2/7/12
to
In TXR Lisp:

(mapcar (fun list) '(a b c d) (range 0))

Or, Lisp-1 style:

[mapcar list '(a b c d) (range 0)]

(range 0) makes an infinite stream (lazy list) counting from 0. But of course,
mapcar stops at the shortest list. So, no screwing around with (length list).

Also:

(collect-each (item '(a b c d))
(count (range 0))
'(,item ,count)) ;; yes, apostrophe is quote and backquote, in one!

Here is a nice trick. In the each*/collect-each* constructs, durnig the binding
phase, the parallel iteration variables are bound to lists, not to items.
So you can do this:

(let ((alist '((a . 1) (b . 2) (c . 3) (d . 4))))
(each* (key '(a b c d))
(val [mapcar* (op (cdr (assoc @1 alist)) key]) ;; key & val are lists
(format "key = ~s, vale = ~s\n" key val))) ;; key & val are items

You can just squint your eyes and use your let* intution when writing the
binding part, but then the same variable names walk the lists. This tidies the
code of having too many dummy variables.

Because mapcar* is used (lazy mapcar), the list is not computed upfront but
lazily during the iteration.

Infinite sequence of powers of two:

(mapcar* (op expt 2) (range 0))

Take the first eight:

[(mapcar* (op expt 2) (range 0)) 0..8]

0..8 is a sugar which means, precisely, (cons 0 8), and [...] allows
a list in the first position, whereby indexing and slicing is supported.

Hitting the the command line:

$ ./txr -c '@(bind x @[(mapcar* (op expt 2) (range 0)) 0..8])'
x[0]="1"
x[1]="2"
x[2]="4"
x[3]="8"
x[4]="16"
x[5]="32"
x[6]="64"
x[7]="128"

Bignums:

$ ./txr -c '@(bind x @[(mapcar* (op expt 2) (range 0)) 200..210])'
x[0]="1606938044258990275541962092341162602522202993782792835301376"
x[1]="3213876088517980551083924184682325205044405987565585670602752"
x[2]="6427752177035961102167848369364650410088811975131171341205504"
x[3]="12855504354071922204335696738729300820177623950262342682411008"
x[4]="25711008708143844408671393477458601640355247900524685364822016"
x[5]="51422017416287688817342786954917203280710495801049370729644032"
x[6]="102844034832575377634685573909834406561420991602098741459288064"
x[7]="205688069665150755269371147819668813122841983204197482918576128"
x[8]="411376139330301510538742295639337626245683966408394965837152256"
x[9]="822752278660603021077484591278675252491367932816789931674304512"

*wink*

WJ

unread,
Mar 6, 2012, 5:19:34 AM3/6/12
to
NewLisp:

> (map (fn (c) (list c $idx)) (explode "trash"))
(("t" 0) ("r" 1) ("a" 2) ("s" 3) ("h" 4))

Marco Antoniotti

unread,
Mar 6, 2012, 1:56:47 PM3/6/12
to
On Tuesday, March 6, 2012 5:19:34 AM UTC-5, WJ wrote:
> Joseph Taylor wrote:
>
> > On Feb 5, 1:56 pm, Brian Houser
It does not work. Yawn. Ronf.
--
MA

WJ

unread,
Mar 13, 2012, 2:33:22 AM3/13/12
to
Clojure:

user=> (map-indexed list "ABC")
((0 \A) (1 \B) (2 \C))

helmut.r...@gmail.com

unread,
Mar 31, 2012, 4:29:43 AM3/31/12
to
Declare a dynamic/special variable. Now *INDEX* is visible to any function called by MAP-INDEX.

(defun map-index (type fn &rest seqs)
(declare (special *index*))
(setf *index* -1)
(apply #'map
type
(lambda (&rest args)
(incf *index*)
(apply fn args))
seqs))

(map-index 'list (lambda (x) (cons x *index*)) '(a b c d e f))
=> ((a . 0) (b . 1) (c . 2) (d . 3) (e . 4) (f . 5))

namekuseijin

unread,
Mar 31, 2012, 8:51:26 PM3/31/12
to
scheme:

(define (map-indexed f ls)
(let g ((i 0) (ls ls))
(if (null? ls) '()
(cons (f (car ls) i)
(g (+ 1 i) (cdr ls))))))

(map-indexed (lambda (x index) (odd? index)) (string->list "foobar"))

WJ

unread,
Apr 27, 2012, 1:16:11 AM4/27/12
to
Racket:

(for/list ([(x i) (in-indexed '(a b c))]) (list x i))
=> ((a 0) (b 1) (c 2))

WJ

unread,
Jan 7, 2015, 11:28:33 PM1/7/15
to
Gauche Scheme:

(use gauche.sequence)
(map-with-index list "trash")
===>
((0 #\t) (1 #\r) (2 #\a) (3 #\s) (4 #\h))

Daniel Torrido

unread,
Jan 9, 2015, 12:36:37 PM1/9/15
to

Another way, a simple proof to show that gauche is totally unnecessary and CL
rocks.

(map 'list (.$ #'string-upcase #'intern) "string")

given

(defun .$(&rest flist)
(lambda(x)(loop with res = x for f in flist
do (setf res (funcall f res)) finally (return res))))

WJ

unread,
Jan 9, 2015, 2:04:52 PM1/9/15
to
Another way:

gosh> (use srfi-42)
#<undef>
gosh> (list-ec (: c (index i) "trash") (list i c))

WJ

unread,
Jan 9, 2015, 4:33:40 PM1/9/15
to
Racket:

> (require srfi/42)

WJ

unread,
Jan 18, 2015, 7:41:30 AM1/18/15
to
elisp:

(require 'dash)

(-map-indexed #'list '(a b c d e f g))
===>
((0 a) (1 b) (2 c) (3 d) (4 e) (5 f) (6 g))

Kaz Kylheku

unread,
Jan 18, 2015, 12:18:51 PM1/18/15
to
On 2015-01-18, WJ <w_a_...@yahoo.com> wrote:
> elisp:
>
> (require 'dash)
>
> (-map-indexed #'list '(a b c d e f g))
> ===>
> ((0 a) (1 b) (2 c) (3 d) (4 e) (5 f) (6 g))

Indexed mapping functions are dumb. Mapcar already has multiple list arguments.
If you want numbering, make one of them an infinite list of numbers.

$ txr -p "[mapcar list (range 10) '(a b c d)]"
((10 a) (11 b) (12 c) (13 d))

See, we have a nice place to put in arguments which modify the sequence. We
can start from 10 instead of zero, and we can skip by deltas other than 1 and
so on.

$ txr -p "[mapcar list (range 10 -1) '(a b c d)]"
((10 a) (9 b) (8 c) (7 d))

WJ

unread,
Jan 8, 2016, 10:59:16 PM1/8/16
to
Why this is marked as abuse? It has been marked as abuse.
Report not abuse
MatzLisp (Ruby):

%w(a b c d e f).each_with_index.to_a
==>[["a", 0], ["b", 1], ["c", 2], ["d", 3], ["e", 4], ["f", 5]]

--
[I]n 2005, 37,460 white females were sexually assaulted or raped by a black
man, while between zero and ten black females were sexually assaulted or raped
by a white man. http://archive.frontpagemag.com/readArticle.aspx?ARTID=26368
[T]he two races, equally free, cannot live under the same government.
--- Thomas Jefferson
0 new messages