[Function]
(map-objects function objects {keyword value}*)

Maps a function of one argument over a list or seq of objects according to the specified keyword arguments. Returns no values.

map-objects supports the following keyword arguments:

:start number
The initial index in objects to begin mapping. The default value is 0.
:end number
The index in objects to stop mapping. The last object mapped is at end-1. Defaults to the length of objects.
:step number
The increment between mapped objects. For example, a value of 2 maps function over every other object between the starting and ending indices in objects. The default value is 1.
:width number
If the value is greater than one then function is passed lists containing length number of adjacent objects in objects. The default value is 1.
:at list
If specified then list contains the explicit positions in objects to map function over and any :start, :step or :end values are ignored.
:class class
If specified then only objects of type class are mapped. The value must be an actual class object, not the name of a class.
:test testfn
If specified then testfn is a predicate of one argument that is applied to each mapped object to determine if function should be called.
:key keyfn
If specified then keyfn is a function of one argument that is applied to each mapped object to produce the value passed to function.
:slot symbol
If specified, then symbol names a slot in each mapped object whose value is passed to function . In this case map-objects is effectively mapping slot values rather than objects.
:slot! symbol
Like :slot except that the slot is assigned the value returned by function for each mapped object.

Examples:

Example 1. Positional mapping.

;;; define some random midi events to demonstrate mapping
(define midis
  (loop for i below 100
        collect (new midi :time i :keynum (between 20 100)
                     :amplitude (between .1 .9)
                     :duration (pick .2 .4 .6 .8))))

;;; Print first 10 objects
(map-objects #'print midis :end 10)

#i(midi time 0 keynum 33 duration 0.2 amplitude 0.18030289) 
#i(midi time 1 keynum 80 duration 0.6 amplitude 0.2407172) 
#i(midi time 2 keynum 89 duration 0.6 amplitude 0.5423868) 
#i(midi time 3 keynum 83 duration 0.8 amplitude 0.23549244) 
#i(midi time 4 keynum 20 duration 0.6 amplitude 0.37683246) 
#i(midi time 5 keynum 78 duration 0.4 amplitude 0.11127909) 
#i(midi time 6 keynum 67 duration 0.4 amplitude 0.4439199) 
#i(midi time 7 keynum 85 duration 0.6 amplitude 0.84430504) 
#i(midi time 8 keynum 56 duration 0.2 amplitude 0.16837305) 
#i(midi time 9 keynum 31 duration 0.4 amplitude 0.15747735) 

;;; print every other midi event
(map-objects #'print midis :end 10 :step 2)

#i(midi time 0 keynum 33 duration 0.2 amplitude 0.18030289) 
#i(midi time 2 keynum 89 duration 0.6 amplitude 0.5423868) 
#i(midi time 4 keynum 20 duration 0.6 amplitude 0.37683246) 
#i(midi time 6 keynum 67 duration 0.4 amplitude 0.4439199) 
#i(midi time 8 keynum 56 duration 0.2 amplitude 0.16837305) 

;;; print just durations in first 10 objects
(map-objects #'print midis :end 10 :slot 'duration)

0.2 
0.6 
0.6 
0.8 
0.6 
0.4 
0.4 
0.6 
0.2 
0.4 

;;; print time values, map four objects at a time
(map-objects #'print midis :start 10 :end 20 :step 2
             :width 4 :slot 'time)

(10 11 12 13) 
(12 13 14 15) 
(14 15 16 17) 
(16 17 18 19) 
(18 19 20 21) 

;;; print only even keynums
(map-objects #'print midis :end 10 :slot 'keynum :test #'even?)

80 
20 
78 
56

;;; print the 49th and 50th keynums
(map-objects #'print midis :at '(49 50) :slot 'keynum)

77
82

Example 2. Slot Editing.

;;; now transpose objects with even keynums by one octave
(map-objects (lambda (x) (+ x 12))
             midis :test #'even? :slot! 'keynum)

;;; print the new even keynum values
(map-objects #'print midis :end 10 :slot 'keynum :test #'evenp)

92 
32 
90 
68 

;;; double the duration of loud events
(map-objects (lambda (x) (sv* x :duration 2))
             midis
             :test (lambda (x) (> (sv x :amplitude) .7)))

See also: