Если вы только начали изучать ракетку, я очень рекомендую против for
и for/list
.Сначала вы должны понять основы: что такое список.
Список (также известный как связанный список):
empty
;или - a
cons
элемента с другим списком
Например,
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
, если lst
равно cons
.Ошибка, если lst
является empty
.Например, (first (cons 2 (cons 1 empty)))
оценивается как 2
, но (first empty)
приводит к ошибке. (rest lst)
: возвращает остаток от lst
, если lst
равно cons
.Ошибка, если 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
Как упоминал Оскар Лопес, хотя список выглядит как массив, способ думать о них очень отличается.Использование 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)
В вашем случае вы, вероятно,want:
;; 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)