0

What are some good ways to perform a sliding window over a finite sequence in Racket, such as finding the highest sum of any sub-sequence of 4 numbers?

(define example #(3 1 4 5 10 23 1 50 0 12 40 12 43 20))
Meow
  • 1,610
  • 1
  • 14
  • 18

2 Answers2

1

First find prefix sums:

#lang racket
(define example #(3 1 4 5 10 23 1 50 0 12 40 12 43 20))

(define-values (sums sum)
  (for/fold ([sums '()] [sum 0]) ([x example])
    (values (cons sum sums) (+ sum x))))
(list->vector (cons sum sums))

Result:

'#(224 204 161 149 109 97 97 47 46 23 13 8 4 3 0)

Then ... profit.

Where profit could be this:

#lang racket
(define example #(3 1 4 5 10 23 1 50 0 12 40 12 43 20))

(define (prefix-sums xs)
  (define-values (sums sum)
    (for/fold ([sums '()] [sum 0]) ([x xs])
      (values (cons sum sums) (+ sum x))))
  (list->vector (reverse (cons sum sums))))

(define (sum4 xs i)
  (- (vector-ref xs (+ i 4))
     (vector-ref xs    i)))

(define (sum4s xs)
  (for/list ([i (- (vector-length xs) 4)])
    (sum4 (prefix-sums xs) i)))

(apply max (sum4s example))
soegaard
  • 30,661
  • 4
  • 57
  • 106
1

For a more generic approach, here's a sequence constructor that returns a sliding window of len elements from a vector, len values at a time, which can then be used with for comprehensions:

(define (in-vector-window v len)
  (make-do-sequence
   (lambda ()
     (values
      (lambda (i) (vector->values v i (+ i len)))
      add1
      0
      (lambda (i) (<= (+ i len) (vector-length v)))
      #f
      #f))))

And some example usages:

> (for/list ([(a b c d) (in-vector-window example 4)]) (list a b c d))
'((3 1 4 5) (1 4 5 10) (4 5 10 23) (5 10 23 1) (10 23 1 50) (23 1 50 0) (1 50 0 12) (50 0 12 40) (0 12 40 12) (12 40 12 43) (40 12 43 20))
> (define sums (for/list ([(a b c d) (in-vector-window example 4)]) (+ a b c d)))
> (foldl max (car sums) (cdr sums))
115
Shawn
  • 47,241
  • 3
  • 26
  • 60