Как построить процедуру скользящего окна, используя ракетку / схему?

Когда написано таким образом, ошибка говорит: 4 части после, если:

(define (rolling-window l size)
  (if (< (length l) size) l
  (take l size) (rolling-window (cdr l) size)))

и когда есть еще один довод сделать это из 3 частей:

(define (rolling-window l size)
  (if (< (length l) size) l
  ((take l size) (rolling-window (cdr l) size))))

тогда это говорит: заявление: не процедура;

4 ответа

Как написать более одного выражения в if еще в ракетке / схеме?

Ну, это не совсем вопрос. Вопрос в том, "Как построить процедуру скользящего окна с использованием ракетки?", Во всяком случае, похоже, что вы, вероятно, из другого языка программирования. Обработка связанных списков поначалу может быть немного сложнее. Но помните, чтобы вычислить длину списка, вы должны перебирать весь список. Итак, используя length это немного анти-паттерн здесь.

Вместо этого я бы порекомендовал вам создать auxИлиарная процедура внутри вашего rolling-window Процедура, которая создает окно при переборе списка. Таким образом, вам не нужно тратить итерации, считая элементы списка.

Тогда если ваш aux процедура всегда возвращает и пустое окно, вы знаете, что вы закончили вычислять окна для данного списка ввода.

(define (rolling-window n xs)
  (define (aux n xs)
    (let aux-loop ([n n] [xs xs] [k identity])
      (cond [(= n 0) (k empty)] ;; done building sublist, return sublist
            [(empty? xs) empty] ;; reached end of xs before n = 0, return empty window
            [else (aux-loop (sub1 n) (cdr xs) (λ (rest) (k (cons (car xs) rest))))]))) ;; continue building sublist

  (let loop ([xs xs] [window (aux n xs)] [k identity])
    (cond ([empty? window] (k empty)) ;; empty window, done
          ([empty? xs] (k empty))     ;; empty input list, done
          (else (loop (cdr xs) (aux n (cdr xs)) (λ (rest) (k (cons window rest)))))))) ;; continue building sublists

(rolling-window 3 '(1 2 3 4 5 6))
;; => '((1 2 3) (2 3 4) (3 4 5) (4 5 6))

Работает на пустые окна

(rolling-window 0 '(1 2 3 4 5 6))
;; => '()

И пустые списки тоже

(rolling-window 3 '())
;; => '()

Вот альтернатива:

#lang racket

(define (rolling-window n xs)
  (define v (list->vector xs))
  (define m (vector-length v))
  (for/list ([i (max 0 (- m n -1))])
    (vector->list (vector-copy v i (+ i n)))))

(rolling-window 3 '(a b c d e f g))
(rolling-window 3 '())
(rolling-window 0 '(a b c))

Выход:

'((a b c) (b c d) (c d e) (d e f) (e f g))
'()
'(() () () ())   ; lack of spec makes this ok !

Следующая модификация функции OP работает. Он включает в себя outlist, для которого начальным значением по умолчанию является пустой список. Списки добавляются в этот список до (length l) меньше чем size,

(define (rolling-window l size (ol '()))
  (if (< (length l) size)  (reverse ol)
      (rolling-window (cdr l) size (cons (take l size) ol))))

Тестирование:

(rolling-window '(1 2 3 4 5 6) 2)
(rolling-window '(1 2 3 4 5 6) 3)
(rolling-window '(1 2 3 4 5 6) 4)

Выход:

'((1 2) (2 3) (3 4) (4 5) (5 6))
'((1 2 3) (2 3 4) (3 4 5) (4 5 6))
'((1 2 3 4) (2 3 4 5) (3 4 5 6))

Какие-нибудь улучшения в этом?

(define (rolling-window l size)
  (cond ((eq? l '()) '())
        ((< (length l) size) '())
        ((cons (take l size) (rolling-window (cdr l) size)))))
Другие вопросы по тегам