Reputation: 345
If I have a list and I map a lambda function over it how can I get a reference to the next or previous item while processing the current one?
(map (lambda (x) x) '(1 2 3))
How would I reference the previous or next element while processing x?
Upvotes: 2
Views: 234
Reputation: 70175
Start with your one list, construct two other lists, one 'shifted' right, and the other 'shifted' left. Like this:
(define (process func x)
(let ((to-front (cons 'front (reverse (cdr (reverse x)))))
(to-rear (append (cdr x) (list 'rear))))
(map func to-front x to-rear)))
Note that the stuff above with reverse
is because map
expects all lists to have the same length. So when adding to the front, you need to remove one from the tail.
Also, the provided func
needs to accept three arguments.
> (process list '(a b c))
((front a b) (a b c) (b c rear))
Upvotes: 3
Reputation: 48745
John McCarthy originally made maplist
and it's defined in CL
still and predates map(car)
. It's definition in Scheme would be something like:
(define (maplist fun lst)
(if (null? lst)
'()
(cons (fun lst) (maplist fun (cdr lst)))))
(maplist values '(1 2 3 4)) ; ==> ((1 2 3 4) (2 3 4) (3 4) (4))
It's slightly more difficult to get each element like map
but if you need more than the first then it's perfect.
Upvotes: 4
Reputation: 16260
For simplicity let's take the case of two elements at a time -- the current and next one. So if you have (list 1 2 3)
, and a function that takes this
and next
args, you want it to be called with:
1 2
2 3
3 <some value, let's say 3>
You could write that concisely as:
(map f xs (append (drop xs 1) (list (last xs))))
However the drop
and append
-ing means that's not the fastest way to do it. Instead you could write a map-slide-pairs
function to do it more directly:
#lang racket/base
(require racket/match)
;; map a list as "sliding pairs". For example:
;; (map-slide-pairs cons '(1 2 3)) ==> '((1 . 2)
;; (2 . 3)
;; (3 . 3))
(define (map-slide-pairs f xs #:last-val [last-val #f])
;; Concise implementation:
;; (map f xs (append (drop xs 1) (list (last xs)))))
;; Faster implementation:
(let loop ([xs xs])
(match xs
[(list) (list)]
[(list this) (list (f this (or last-val this)))]
[(list this next more ...) (cons (f this next)
(loop (cons next more)))])))
(module+ test
(require rackunit)
(check-equal? (map-slide-pairs cons '(1 2 3))
'([1 . 2][2 . 3][3 . 3]))
(check-equal? (map-slide-pairs cons '(1 2 3) #:last-val 100)
'([1 . 2][2 . 3][3 . 100])))
Hopefully you can see how to extend this and make a "map-slide-triples
" function that would be called with the previous, current, and next elements of the list.
Upvotes: 2
Reputation: 685
You can always use map
on two zip
ped lists, i.e.
(import (srfi srfi-1)) ; or use some zip implementation
(define a '(1 2 3 4 5))
(map (lambda (x) x)
(zip a
(append (cdr a) (list (car a)))))
which results in ((1 2) (2 3) (3 4) (4 5) (5 1))
.
Of course, the above assumes "periodic" boundary conditions for the lists (you should modify the boundary conditions for your case).
And also you would need to modify the lambda
to handle pairs of elements.
Upvotes: 2