вернуть список с результатами выполнения цикла for - PullRequest
0 голосов
/ 01 февраля 2019

Я только начал изучать ракетку, и мне нужно зациклить список с индексом.

Теперь я использую для :

#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?

Ответы [ 2 ]

0 голосов
/ 01 февраля 2019

Если вы только начали изучать ракетку, я очень рекомендую против 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)
0 голосов
/ 01 февраля 2019

Для начала, использование индексов является наихудшим из возможных способов обхода списка, и его следует избегать: каждая 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 вместо этого, который оптимизирован для быстрого поиска элементов с использованием индексов.

...