Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 115 lines (107 sloc) 4.645 kb
0bec1f6 @greghendershott Add in-take-list sequence.
authored
1 #lang racket
2
f705155 @greghendershott Delete filter-take
authored
3 (provide in-take)
0bec1f6 @greghendershott Add in-take-list sequence.
authored
4
5 ;; Background: Functions like `hash', `hash-set*', `dict-set*' and so
6 ;; on take argument couples as alternating arguments rather than a
7 ;; cons pair. Using such functions can be refreshing, as you can type
8 ;; simply (hash k0 v0 k1 v1) instead of all the dots and parens with
f705155 @greghendershott Delete filter-take
authored
9 ;; #hash([k0 . v0][k1 v2]).
0bec1f6 @greghendershott Add in-take-list sequence.
authored
10 ;;
f705155 @greghendershott Delete filter-take
authored
11 ;; Using such functions is nice, but defining them is a bit awkward --
12 ;; unless you have in-take. It lets you sequence a flat list of items
13 ;; in groups of N, much like using `take' and `drop'.
14 ;;
15 ;; Likewise, this makes it easy to write simple flat wrappers. For example
0bec1f6 @greghendershott Add in-take-list sequence.
authored
16 ;; here is a `hash'-like initializer for association lists:
17 ;;
18 ;; (define (alist . xs)
bd15932 @greghendershott Stream-based implementation.
authored
19 ;; (for/list ([(k v) (in-take xs 2)])
0bec1f6 @greghendershott Add in-take-list sequence.
authored
20 ;; (cons k v)))
21 ;;
7a2028d @greghendershott Describe the generalizing in comments.
authored
22 ;; Generalizing:
23 ;;
24 ;; 1. At first I wrote this for couples in lists.
25 ;;
26 ;; 2. Then I generalized it to any group size -- couples, triples,
27 ;; whatever -- in lists.
28 ;;
f705155 @greghendershott Delete filter-take
authored
29 ;; 3. Then I generalized it to any single-valued sequence: list,
30 ;; vector, string, etc.
0bec1f6 @greghendershott Add in-take-list sequence.
authored
31
32 (define (make-fill who n)
33 (lambda (_)
34 (error who "list not multiple of ~a items" n)))
35
36 (define fill/c (exact-nonnegative-integer? . -> . any/c))
37
bd15932 @greghendershott Stream-based implementation.
authored
38 ;; (in-take seq n fill) is a way to take `n' elements at a time from
39 ;; `seq'. For instance with n=2 you will get successive couples of
40 ;; elements, with n=3 you get triples, and so on. `n' defaults to 2.
41 ;; If there aren't exactly `n' elements at the end of the list, `fill'
42 ;; is called with an index from 0 to (sub1 n). `fill' defaults to a
43 ;; procedure that raises an error, but you may supply a procedure that
44 ;; "fills in missing values".
30c3f1d @greghendershott Remove unnecessary require. Add comment.
authored
45 ;;
46 ;; Note: Just as I was finishing this, I discovered `in-slice' in
47 ;; racket/unstable. Although that's great as far as it goes, I've
48 ;; found that my optional `fill' functionality to handle missing
49 ;; values is very useful.
bd15932 @greghendershott Stream-based implementation.
authored
50
51 (define/contract (in-take seq [n 2] [fill (make-fill 'in-take n)])
52 ((sequence?) (exact-positive-integer? fill/c) . ->* . sequence?)
4be1db3 @greghendershott Use `make-do-sequence', following examples in unstable/sequence.
authored
53 (make-do-sequence ;Model: unstable/sequence
54 (lambda ()
55 (define-values (more? get) (sequence-generate seq))
56 (values (lambda (_) ;pos->element
57 (apply values (for/list ([i n])
58 (cond [(more?) (get)]
59 [else (fill i)]))))
60 (lambda (_) #t) ;next-pos
61 #t ;initial-pos
62 (lambda (_) (more?)) ;continue-with-pos?
63 (lambda _ #t) ;continue-with-val?
64 (lambda _ #t) ;continue-after-pos+val?
65 ))))
0bec1f6 @greghendershott Add in-take-list sequence.
authored
66
67 (module+ test
f705155 @greghendershott Delete filter-take
authored
68 (require rackunit)
0bec1f6 @greghendershott Add in-take-list sequence.
authored
69 (test-case
5dd972c @greghendershott Generalize `X-take-list' functions to `X-take'.
authored
70 "in-take"
bd15932 @greghendershott Stream-based implementation.
authored
71 ;; Take from an empty sequence is '() (not an error)
72 (check-equal? (for/list ([(k v) (in-take (list))])
73 (cons k v))
74 '())
75 (check-equal? (for/list ([(k v) (in-take (vector))])
76 (cons k v))
77 '())
78 (check-equal? (for/list ([(k v) (in-take "")])
79 (cons k v))
80 '())
5dd972c @greghendershott Generalize `X-take-list' functions to `X-take'.
authored
81 ;; Sequence is multiple of take size
82 (check-equal? (for/list ([(k v) (in-take (list 'a "1" 'b "2"))])
83 (cons k v))
84 '([a . "1"][b . "2"]))
85 (check-equal? (for/list ([(k v) (in-take (vector 'a "1" 'b "2"))])
86 (cons k v))
87 '([a . "1"][b . "2"]))
88 (check-equal? (for/list ([(k v) (in-take "a1b2")])
89 (cons k v))
90 '([#\a . #\1][#\b . #\2]))
91 ;; Missing values raising an error (the default `fill')
92 (check-exn exn:fail?
93 (lambda () (for/list ([(k v) (in-take '(a "1" b "2" c) 2)])
94 (cons k v))))
95 ;; Missing values filled in
96 (check-equal? (for/list ([(k v) (in-take '(a "1" b "2" c) 2
97 (const "FILL"))])
98 (cons k v))
99 '([a . "1"][b . "2"][c . "FILL"]))
100 ;; Fill function is passed expected "index"
101 (check-equal? (for/list ([(a b c d e) (in-take '(0 1) 5 values)])
102 (list a b c d e))
103 '((0 1 2 3 4))) ;fill was called with 2 3 4
104 ;; Taking the same list with different take-sizes.
0bec1f6 @greghendershott Add in-take-list sequence.
authored
105 (define test-xs (list 0 1 2 3 4 5 6 7 8 9))
5dd972c @greghendershott Generalize `X-take-list' functions to `X-take'.
authored
106 (define (test-take n)
107 (for/list ([ts (in-values-sequence (in-take test-xs n))])
108 ts))
109 (check-equal? (test-take 1)
0bec1f6 @greghendershott Add in-take-list sequence.
authored
110 '((0) (1) (2) (3) (4) (5) (6) (7) (8) (9)))
5dd972c @greghendershott Generalize `X-take-list' functions to `X-take'.
authored
111 (check-equal? (test-take 2)
0bec1f6 @greghendershott Add in-take-list sequence.
authored
112 '((0 1) (2 3) (4 5) (6 7) (8 9)))
5dd972c @greghendershott Generalize `X-take-list' functions to `X-take'.
authored
113 (check-equal? (test-take 5)
0bec1f6 @greghendershott Add in-take-list sequence.
authored
114 '((0 1 2 3 4) (5 6 7 8 9)))))
Something went wrong with that request. Please try again.