Scheme 将索引作为LISP中参数之一的映射函数
LISP语言中是否有任何内置函数(特别是Racket)可以像map一样工作,但将元素的索引作为参数之一传递给mapping函数 此类功能的示例如下:Scheme 将索引作为LISP中参数之一的映射函数,scheme,lisp,racket,Scheme,Lisp,Racket,LISP语言中是否有任何内置函数(特别是Racket)可以像map一样工作,但将元素的索引作为参数之一传递给mapping函数 此类功能的示例如下: (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
(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))
显然,这不是一个非常有效的实现,并且不像常规映射那样支持多个列表作为参数。不完全是这样,但是对于类似的目标,还有其他一些东西,比如使用或 例如,模式不是
(地图索引f lst)
,而是
(for/list ([x lst] [i (in-naturals)]) (f x i))
或
这两种模式中的任何一种都可以用来实现映射索引
,以及映射
和构建列表
的组合
Racket的迭代形式(如)比一组固定的映射函数更灵活
具体例子:
> (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))
或者,如果您仍然需要映射索引
函数,则可以使用此函数更简洁地定义它
> (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
过程编写一个非常简单的映射索引版本,并映射结果:
(define (map-index-1 f xs)
(map f xs (range (length xs))))
在某些情况下,您可能希望首先使用索引:
(define (map-index-2 f xs)
(map f (range (length xs)) xs))
如果希望能够对多个列表使用映射索引
,可以将列表参数传递给可选参数。这里,apply
将map
过程应用于由函数f
构建的列表、输入列表和范围
列表:
(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>(地图索引-2 cons'(a b c d))
“((0.a)(1.b)(2.c)(3.d))
scratch.rkt>(map-index-3列表(abcd)’(一二三四)’(wxyz))
"(a一w 0)(b二x 1)(c三y二)(d四z三)
scratch.rkt>(map-index-4列表(abcd)’(一二三四)’(wxyz))
"(0a1w)(1b2x)(2c3y)(3d4z)
计划
标准Scheme没有内置的范围
过程,但编写一个简单的版本非常容易。这些解决方案适用于任何R4RS、R5RS、R6RS或R7RS方案实现。此版本的范围
所做的工作超出了当前应用程序的要求,它采用了一个步骤
参数,可以是正参数,也可以是负参数:
(define (range start stop step)
(if (or (and (> step 0)
(>= start stop))
(and (<= step 0)
(<= start stop)))
'()
(cons start (range (+ start step) stop step))))
>(地图索引-5 cons'(a b c d))
((a.0)(b.1)(c.2)(d.3))
>(地图索引-6 cons(a b c d))
((0.a)(1.b)(2.c)(3.d))
>(map-index-7列表’(AB c d)‘一二三四’(w x y z))
((a一w 0)(b二x一)(c三y二)(d四z三))
>(地图索引-8列表’(AB c d)‘一二三四’(w x y z))
((0A一w)(1B二x)(2C三y)(3D四z))
标准方案的映射范围程序
通过利用范围
函数的功能,该方法可以扩展到使用可能不代表指数的更复杂范围内的数字。使用上面的范围
定义,此映射范围
过程仍然适用于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)))))
>(地图范围CONS2'(a b c d))
((2.a)(4.b)(6.c)(8.d))
>(地图范围列表5’(a b c d)‘一二三四’(w x y z))
((5A一w)(10B二x)(15C三y)(20D四z))
>(地图范围cons 2-2’(a b c d))
((2.a)(0.b)(-2.c)(-4.d))
>(地图范围列表5-5’(a b c d)‘一二三四’(w x y z))
((5a1w)(0b2x)(-5c3y)(-10d4z))
查看在破折号中为emacs索引的地图。它能满足你的需求。
感谢您详尽的回答。我认为在球拍中最好使用for/list,但在其他方言中可能是这样。我只是不确定性能,AFAIK这可以使用foldl/foldr实现,牺牲过程中的可读性。@AdamŠtafa--for/list
在任何其他方案方言AFAIK中都不可用;我写这个答案的主要原因是为了说明如何在可移植方案中实现您的目标。但是对于地图索引的最简单的情况
,我可能会使用(地图f x(范围(长度x))
,即使在球拍中也是如此。我个人觉得它比(for/list([(x I)(在索引lst中)](f x I))更简洁易读
;如果存在显著的性能差异,我会感到惊讶,但您可以随时进行测量和比较。
(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))))
(define (map-range f start step . xs)
(let ((stop (+ start (* step (length (car xs))))))
(apply map (cons f
(cons (range start stop step)
xs)))))