如果你刚刚开始学习 Racket,我真的不推荐 for 和 for/list。你应该先了解基本的:什么是列表。
列表(也称为链表)是:
例如,
-
empty 是一个空列表。
-
(cons 9 empty) 是一个包含一个元素的列表:9。
-
(cons 3 (cons 9 empty)) 是一个包含两个元素的列表:3 和 9。
给定一个列表,以下是您可以执行的基本操作(cons 除外)。
-
(empty? lst):检查lst是否为empty。例如,(empty? empty) 的计算结果为 #t,但 (empty? (cons 1 empty)) 的计算结果为 #f。
-
(first lst):如果lst 是cons,则返回lst 的第一个元素。如果lst 是empty,则会出错。例如,(first (cons 2 (cons 1 empty))) 的计算结果为 2,但 (first empty) 会导致错误。
-
(rest lst):如果lst 是cons,则返回lst 的其余部分。如果lst 是empty,则会出错。例如,(rest (cons 2 (cons 1 empty))) 的计算结果为 (cons 1 empty),但 (first empty) 会导致错误。
结合使用first 和rest,您可以访问任何元素。如果您有一个列表 (cons 5 (cons 4 (cons 3 (cons 2 empty)))) 并且您想要访问第二个元素(应该是 4),您将计算:
-
(rest lst) 这会给你(cons 4 (cons 3 (cons 2 empty)))
-
(first (rest lst)) 会给你4。
list 只是简单的缩写,可以轻松构建列表
-
(list) 是 empty 的缩写。
-
(list 9) 是 (cons 9 empty) 的缩写
-
(list 1 2 3) 是 (cons 1 (cons 2 (cons 3 empty))) 的缩写。
其他列表操作仅使用上述原始操作来实现。比如list-ref的实现如下:
(define (my-list-ref xs i)
(cond
;; a list is either empty
[(empty? xs) (error 'out-of-bound)]
;; or a cons, where it's safe to use first and rest
[(= i 0) (first xs)]
[else (my-list-ref (rest xs) (- i 1))]))
;; (my-list-ref (list) 0) => out-of-bound error
;; (my-list-ref (list 4 5 6) 0) => 4
;; (my-list-ref (list 4 5 6) 1) => 5
;; (my-list-ref (list 4 5 6) 2) => 6
正如 Óscar López 所提到的,虽然列表看起来类似于数组,但考虑它们的方式却大不相同。使用list-ref 需要O(i),如果您想一次获取第i 个元素,这很好,但它不是访问所有元素(甚至很多元素)的正确方法。相反,只需一次访问所有这些。例如,如果我有一个列表 (list 2 3 4),并且我想获得另一个列表,并将 10 添加到原始列表的每个元素中,我会写:
(define (add10-all xs)
(cond
;; a list is either empty, where (add10-all empty) should return empty
[(empty? xs) empty]
;; or a cons, where we want to to add 10 to the first element,
;; recur on the rest, and create a resulting cons
[else (cons (+ 10 (first xs)) (add10-all (rest xs)))]))
;; (add10-all (list)) => (list)
;; (add10-all (list 2 3 4)) => (list 12 13 14)
在你的情况下,你可能想要:
;; assume function-numeric consumes an element from list1 and the whole list2
;; assume function-no-numeric consumes an element from list1 and the whole list3
(define (foo list1 list2 list3)
(cond
[(empty? list1) empty]
[else
(define e (first list1))
(define out (if (number? e)
(function-numeric e list2)
(function-no-numeric e list3)))
(cons out (foo (rest list1) list2 list3))]))
(foo list1 list2 list3)
或
;; assume function-numeric consumes an element from list1 and the corresponding element in list2
;; assume function-no-numeric consumes an element from list1 and the corresponding element in list3
(define (foo list1 list2 list3)
(cond
[(empty? list1) empty]
[else
(define e (first list1))
(define out (if (number? e)
(function-numeric e (first list2))
(function-no-numeric e (first list3))))
(cons out (foo (rest list1) (rest list2) (rest list3)))]))
(foo list1 list2 list3)
可能是你想做别的事,但结构应该和上面两段代码差不多。例如,如果你碰巧真的需要一个索引来计算function-numeric 和function-no-numeric,你可以这样写:
;; assume function-numeric consumes (1) an element from list1 (2) the corresponding element in list2 (3) an index
;; assume function-no-numeric consumes (1) an element from list1 (2) the corresponding element in list3 (3) an index
(define (foo list1 list2 list3 i)
(cond
[(empty? list1) empty]
[else
(define e (first list1))
(define out (if (number? e)
(function-numeric e (first list2) i)
(function-no-numeric e (first list3) i)))
(cons out (foo (rest list1) (rest list2) (rest list3) (+ i 1)))]))
(foo list1 list2 list3 0)