将索引作为 LISP 中的参数之一的映射函数
Map function with index as one of arguments in LISP
LISP 语言(尤其是 Racket)中是否有任何内置函数可以像 map 一样工作,但将元素的索引作为参数之一传递给映射函数?
此类函数的示例为:
(define map-index (lambda (func list)
(map func list (build-list (length list) (lambda (i) i)))))
;usage:
> (map-index cons '(a b c d))
;output:
'((a . 0) (b . 1) (c . 2) (d . 3))
显然这不是一个非常有效的实现,并且不支持多个列表作为参数,就像常规映射一样。
不完全是,但是还有其他类似的目标,比如 for/list
with in-naturals
or in-indexed
。
例如,模式不是 (map-index f lst)
,而是
(for/list ([x lst] [i (in-naturals)]) (f x i))
或
(for/list ([(x i) (in-indexed lst)]) (f x i))
这些模式中的任何一个都可以用来实现 map-index
以及 map
和 build-list
的组合。
Racket 的迭代形式 for/list
比一组固定的类映射函数更灵活。
具体示例:
> (for/list ([x '(a b c d)] [i (in-naturals)]) (cons x i))
'((a . 0) (b . 1) (c . 2) (d . 3))
> (for/list ([(x i) (in-indexed '(a b c d))]) (cons x i))
'((a . 0) (b . 1) (c . 2) (d . 3))
或者,如果您仍然想要一个 map-index
函数,您可以使用这个来更简洁地定义它。
> (define (map-index f lst)
(for/list ([(x i) (in-indexed lst)]) (f x i)))
> (map-index cons '(a b c d))
'((a . 0) (b . 1) (c . 2) (d . 3))
球拍
您可以使用 Racket range
过程并映射结果来编写 map-index
的极其简单的版本:
(define (map-index-1 f xs)
(map f xs (range (length xs))))
在某些情况下,您可能首先需要索引:
(define (map-index-2 f xs)
(map f (range (length xs)) xs))
如果您希望能够对多个列表使用 map-index
,您可以将列表参数传递给可选参数。此处,apply
将 map
过程应用于由函数 f
、输入列表和 range
列表构建的列表:
(define (map-index-3 f . xs)
(apply map (cons f
(append xs
(list (range (length (car xs))))))))
但是在映射到多个列表时,先放置索引可能更有意义:
(define (map-index-4 f . xs)
(apply map (cons f
(cons (range (length (car xs)))
xs))))
scratch.rkt> (map-index-1 cons '(a b c d))
'((a . 0) (b . 1) (c . 2) (d . 3))
scratch.rkt> (map-index-2 cons '(a b c d))
'((0 . a) (1 . b) (2 . c) (3 . d))
scratch.rkt> (map-index-3 list '(a b c d) '(one two three four) '(w x y z))
'((a one w 0) (b two x 1) (c three y 2) (d four z 3))
scratch.rkt> (map-index-4 list '(a b c d) '(one two three four) '(w x y z))
'((0 a one w) (1 b two x) (2 c three y) (3 d four z))
方案
Standard Scheme 没有内置range
程序,但是写一个简单的版本还是很容易的。这些解决方案适用于任何 R4RS、R5RS、R6RS 或 R7RS 方案实施。这个版本的 range
做的比当前应用程序所需的更多,采用 step
可以是正数或负数的参数:
(define (range start stop step)
(if (or (and (> step 0)
(>= start stop))
(and (<= step 0)
(<= start stop)))
'()
(cons start (range (+ start step) stop step))))
定义了一个 range
过程后,可以在 Scheme 中使用与上述 Racket 解决方案相同的方法:
(define (map-index-5 f xs)
(map f xs (range 0 (length xs) 1)))
(define (map-index-6 f xs)
(map f (range 0 (length xs) 1) xs))
(define (map-index-7 f . xs)
(apply map (cons f
(append xs
(list (range 0 (length (car xs)) 1))))))
(define (map-index-8 f . xs)
(apply map (cons f
(cons (range 0 (length (car xs)) 1)
xs))))
> (map-index-5 cons '(a b c d))
((a . 0) (b . 1) (c . 2) (d . 3))
> (map-index-6 cons '(a b c d))
((0 . a) (1 . b) (2 . c) (3 . d))
> (map-index-7 list '(a b c d) '(one two three four) '(w x y z))
((a one w 0) (b two x 1) (c three y 2) (d four z 3))
> (map-index-8 list '(a b c d) '(one two three four) '(w x y z))
((0 a one w) (1 b two x) (2 c three y) (3 d four z))
一个map-range
标准方案程序
通过利用 range
函数的功能,可以扩展此方法以使用可能不代表索引的更复杂范围内的数字。使用上面的 range
定义,此 map-range
过程仍然适用于 R4RS 到 R7RS 方案实现:
(define (map-range f start step . xs)
(let ((stop (+ start (* step (length (car xs))))))
(apply map (cons f
(cons (range start stop step)
xs)))))
> (map-range cons 2 2 '(a b c d))
((2 . a) (4 . b) (6 . c) (8 . d))
> (map-range list 5 5 '(a b c d) '(one two three four) '(w x y z))
((5 a one w) (10 b two x) (15 c three y) (20 d four z))
> (map-range cons 2 -2 '(a b c d))
((2 . a) (0 . b) (-2 . c) (-4 . d))
> (map-range list 5 -5 '(a b c d) '(one two three four) '(w x y z))
((5 a one w) (0 b two x) (-5 c three y) (-10 d four z))
LISP 语言(尤其是 Racket)中是否有任何内置函数可以像 map 一样工作,但将元素的索引作为参数之一传递给映射函数?
此类函数的示例为:
(define map-index (lambda (func list)
(map func list (build-list (length list) (lambda (i) i)))))
;usage:
> (map-index cons '(a b c d))
;output:
'((a . 0) (b . 1) (c . 2) (d . 3))
显然这不是一个非常有效的实现,并且不支持多个列表作为参数,就像常规映射一样。
不完全是,但是还有其他类似的目标,比如 for/list
with in-naturals
or in-indexed
。
例如,模式不是 (map-index f lst)
,而是
(for/list ([x lst] [i (in-naturals)]) (f x i))
或
(for/list ([(x i) (in-indexed lst)]) (f x i))
这些模式中的任何一个都可以用来实现 map-index
以及 map
和 build-list
的组合。
Racket 的迭代形式 for/list
比一组固定的类映射函数更灵活。
具体示例:
> (for/list ([x '(a b c d)] [i (in-naturals)]) (cons x i))
'((a . 0) (b . 1) (c . 2) (d . 3))
> (for/list ([(x i) (in-indexed '(a b c d))]) (cons x i))
'((a . 0) (b . 1) (c . 2) (d . 3))
或者,如果您仍然想要一个 map-index
函数,您可以使用这个来更简洁地定义它。
> (define (map-index f lst)
(for/list ([(x i) (in-indexed lst)]) (f x i)))
> (map-index cons '(a b c d))
'((a . 0) (b . 1) (c . 2) (d . 3))
球拍
您可以使用 Racket range
过程并映射结果来编写 map-index
的极其简单的版本:
(define (map-index-1 f xs)
(map f xs (range (length xs))))
在某些情况下,您可能首先需要索引:
(define (map-index-2 f xs)
(map f (range (length xs)) xs))
如果您希望能够对多个列表使用 map-index
,您可以将列表参数传递给可选参数。此处,apply
将 map
过程应用于由函数 f
、输入列表和 range
列表构建的列表:
(define (map-index-3 f . xs)
(apply map (cons f
(append xs
(list (range (length (car xs))))))))
但是在映射到多个列表时,先放置索引可能更有意义:
(define (map-index-4 f . xs)
(apply map (cons f
(cons (range (length (car xs)))
xs))))
scratch.rkt> (map-index-1 cons '(a b c d))
'((a . 0) (b . 1) (c . 2) (d . 3))
scratch.rkt> (map-index-2 cons '(a b c d))
'((0 . a) (1 . b) (2 . c) (3 . d))
scratch.rkt> (map-index-3 list '(a b c d) '(one two three four) '(w x y z))
'((a one w 0) (b two x 1) (c three y 2) (d four z 3))
scratch.rkt> (map-index-4 list '(a b c d) '(one two three four) '(w x y z))
'((0 a one w) (1 b two x) (2 c three y) (3 d four z))
方案
Standard Scheme 没有内置range
程序,但是写一个简单的版本还是很容易的。这些解决方案适用于任何 R4RS、R5RS、R6RS 或 R7RS 方案实施。这个版本的 range
做的比当前应用程序所需的更多,采用 step
可以是正数或负数的参数:
(define (range start stop step)
(if (or (and (> step 0)
(>= start stop))
(and (<= step 0)
(<= start stop)))
'()
(cons start (range (+ start step) stop step))))
定义了一个 range
过程后,可以在 Scheme 中使用与上述 Racket 解决方案相同的方法:
(define (map-index-5 f xs)
(map f xs (range 0 (length xs) 1)))
(define (map-index-6 f xs)
(map f (range 0 (length xs) 1) xs))
(define (map-index-7 f . xs)
(apply map (cons f
(append xs
(list (range 0 (length (car xs)) 1))))))
(define (map-index-8 f . xs)
(apply map (cons f
(cons (range 0 (length (car xs)) 1)
xs))))
> (map-index-5 cons '(a b c d))
((a . 0) (b . 1) (c . 2) (d . 3))
> (map-index-6 cons '(a b c d))
((0 . a) (1 . b) (2 . c) (3 . d))
> (map-index-7 list '(a b c d) '(one two three four) '(w x y z))
((a one w 0) (b two x 1) (c three y 2) (d four z 3))
> (map-index-8 list '(a b c d) '(one two three four) '(w x y z))
((0 a one w) (1 b two x) (2 c three y) (3 d four z))
一个map-range
标准方案程序
通过利用 range
函数的功能,可以扩展此方法以使用可能不代表索引的更复杂范围内的数字。使用上面的 range
定义,此 map-range
过程仍然适用于 R4RS 到 R7RS 方案实现:
(define (map-range f start step . xs)
(let ((stop (+ start (* step (length (car xs))))))
(apply map (cons f
(cons (range start stop step)
xs)))))
> (map-range cons 2 2 '(a b c d))
((2 . a) (4 . b) (6 . c) (8 . d))
> (map-range list 5 5 '(a b c d) '(one two three four) '(w x y z))
((5 a one w) (10 b two x) (15 c three y) (20 d four z))
> (map-range cons 2 -2 '(a b c d))
((2 . a) (0 . b) (-2 . c) (-4 . d))
> (map-range list 5 -5 '(a b c d) '(one two three four) '(w x y z))
((5 a one w) (0 b two x) (-5 c three y) (-10 d four z))