我刚刚开始学习球拍,我需要用索引循环播放列表。
现在,我正在使用for:
#lang racket
(for ([index (in-range 0 (length list1))])
(if (number? (list-ref list1 index))
(function-numeric list1 index list2)
(function-no-numeric list1 index list3)))
function-numeric
和function-no-numeric
返回一个列表,我需要使用这些函数返回的列表创建一个列表。但是我不知道该怎么做。
也许使用map可能会更容易,但我不是。
如何通过for循环返回列表列表?
答案 0 :(得分:3)
对于初学者而言,使用索引是遍历列表的最糟糕的方法,应避免使用:每个list-ref
操作都是O(n)
,因为要到达元素i
,您必须遍历所有i-1
个元素,使整个遍历成为一个O(n^2)
操作。如果您绝对需要它们,则使用索引生成一个单独的列表。
为了将返回的数据收集到列表中,我们可以使用for/list
来累积每次迭代的结果,甚至可以并行遍历多个元素序列。让我们放在一起:
(for/list ([element list1]
[index (in-range (length list1))])
(if (number? element)
(function-numeric list1 index list2)
(function-no-numeric list1 index list3)))
我只是希望您不要在list-ref
和function-numeric
中使用function-no-numeric
。也许有一种更好的方法来构造算法,避免完全避免使用索引-列表的使用方式不应与数组相同!如果您的算法无法通过修改来避免使用索引,请考虑使用vector
,该算法已针对使用索引的快速项检索进行了优化。
答案 1 :(得分:2)
如果您刚刚开始学习球拍,我强烈建议您反对for
和for/list
。首先应该了解基本知识:什么是列表。
列表(也称为链接列表)是:
empty
;或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
正如ÓscarLó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)