返回带有for循环执行结果的列表

时间:2019-02-01 17:34:58

标签: functional-programming racket

我刚刚开始学习球拍,我需要用索引循环播放列表。

现在,我正在使用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-numericfunction-no-numeric返回一个列表,我需要使用这些函数返回的列表创建一个列表。但是我不知道该怎么做。

也许使用map可能会更容易,但我不是。

如何通过for循环返回列表列表?

2 个答案:

答案 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-reffunction-numeric中使用function-no-numeric 。也许有一种更好的方法来构造算法,避免完全避免使用索引-列表的使用方式不应与数组相同!如果您的算法无法通过修改来避免使用索引,请考虑使用vector,该算法已针对使用索引的快速项检索进行了优化。

答案 1 :(得分:2)

如果您刚刚开始学习球拍,我强烈建议您反对forfor/list。首先应该了解基本知识:什么是列表。

列表(也称为链接列表)是:

  • empty;或
  • 一个cons元素和另一个列表

例如

  • empty是一个空列表。
  • (cons 9 empty)是一个包含一个元素的列表:9
  • (cons 3 (cons 9 empty))是一个包含两个元素的列表:39

给出一个列表,这是您可以执行的原始操作(除cons之外)。

  • (empty? lst):检查lst是否为empty。例如,(empty? empty)的值为#t,而(empty? (cons 1 empty))的值为#f
  • (first lst):如果lstlst,则返回cons的第一个元素。如果lstempty,则会发生错误。例如,(first (cons 2 (cons 1 empty)))的计算结果为2,但是(first empty)会导致错误。
  • (rest lst):如果lstlst,则返回cons的其余部分。如果lstempty,则会发生错误。例如,(rest (cons 2 (cons 1 empty)))的计算结果为(cons 1 empty),但是(first empty)会导致错误。

结合使用firstrest,您可以访问任何元素。如果您有一个列表(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-numericfunction-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)