LISP 中以索引作为参数之一的映射函数

Ada*_*afa 2 lisp scheme racket

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))
Run Code Online (Sandbox Code Playgroud)

显然,这不是一个非常有效的实现,并且不支持多个列表作为参数,就像常规映射一样。

ex *_*ilo 5


球拍


map-index您可以编写一个使用 Racketrange过程并映射结果的极其简单的版本:

(define (map-index-1 f xs)
  (map f xs (range (length xs))))
Run Code Online (Sandbox Code Playgroud)

在某些情况下,您可能首先需要索引:

(define (map-index-2 f xs)
  (map f (range (length xs)) xs))
Run Code Online (Sandbox Code Playgroud)

如果您希望能够使用map-index多个列表,可以将列表参数传递给可选参数。在这里,apply将该map过程应用于由函数f、输入列表和一个range列表构造的列表:

(define (map-index-3 f . xs)
  (apply map (cons f
                   (append xs
                           (list (range (length (car xs))))))))
Run Code Online (Sandbox Code Playgroud)

但在映射多个列表时,将索引放在前面可能更有意义:

(define (map-index-4 f . xs)
  (apply map (cons f
                   (cons (range (length (car xs)))
                         xs))))
Run Code Online (Sandbox Code Playgroud)
(define (map-index-1 f xs)
  (map f xs (range (length xs))))
Run Code Online (Sandbox Code Playgroud)

方案


标准方案没有内置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))))
Run Code Online (Sandbox Code Playgroud)

定义了一个range过程后,可以在方案中使用与上述 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))))
Run Code Online (Sandbox Code Playgroud)
(define (map-index-2 f xs)
  (map f (range (length xs)) xs))
Run Code Online (Sandbox Code Playgroud)

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)))))
Run Code Online (Sandbox Code Playgroud)
(define (map-index-3 f . xs)
  (apply map (cons f
                   (append xs
                           (list (range (length (car xs))))))))
Run Code Online (Sandbox Code Playgroud)