3.9 Pairs and Lists
Pairs and Lists in Guide: Racket introduces pairs and lists.
A pair combines exactly two values. The first value is accessed with the car procedure, and the second value is accessed with the cdr procedure. Pairs are not mutable (but see Mutable Pairs and Lists).
A list is recursively defined: it is either the constant null, or it is a pair whose second value is a list.
A list can be used as a single-valued sequence (see Sequences). The elements of the list serve as elements of the sequence. See also in-list.
Cyclic data structures can be created using only immutable pairs via read or make-reader-graph. If starting with a pair and using some number of cdrs returns to the starting pair, then the pair is not a list.
3.9.1 Pair Constructors and Selectors
Examples: |
> (pair? 1) |
#f |
> (pair? (cons 1 2)) |
#t |
> (pair? (list 1 2)) |
#t |
> (pair? '(1 2)) |
#t |
> (pair? '()) |
#f |
(build-list n proc) → list? |
n : exact-nonnegative-integer? |
proc : (exact-nonnegative-integer? . -> . any) |
Examples: |
> (build-list 10 values) |
'(0 1 2 3 4 5 6 7 8 9) |
> (build-list 5 (lambda (x) (* x x))) |
'(0 1 4 9 16) |
3.9.2 List Operations
(length lst) → exact-nonnegative-integer? |
lst : list? |
(list-ref lst pos) → any/c |
lst : any/c |
pos : exact-nonnegative-integer? |
Examples: |
> (list-ref (list 'a 'b 'c) 0) |
'a |
> (list-ref (list 'a 'b 'c) 1) |
'b |
> (list-ref (list 'a 'b 'c) 2) |
'c |
(list-tail lst pos) → any/c |
lst : any/c |
pos : exact-nonnegative-integer? |
The last argument need not be a list, in which case the result is an “improper list.”
Examples: |
> (append (list 1 2) (list 3 4)) |
'(1 2 3 4) |
> (append (list 1 2) (list 3 4) (list 5 6) (list 7 8)) |
'(1 2 3 4 5 6 7 8) |
Example: |
> (reverse (list 1 2 3 4)) |
'(4 3 2 1) |
3.9.3 List Iteration
(map proc lst ...+) → list? |
proc : procedure? |
lst : list? |
Examples: | ||||
| ||||
'(2 3 4 5) | ||||
| ||||
'(11 102 1003 10004) |
(andmap proc lst ...+) → any |
proc : procedure? |
lst : list? |
the result is #f if any application of proc produces #f, in which case proc is not applied to later elements of the lsts; and
the result is that of proc applied to the last elements of the lstss; more specifically, the application of proc to the last elements in the lsts is in tail position with respect to the andmap call.
If the lsts are empty, then #t is returned.
Examples: |
> (andmap positive? '(1 2 3)) |
#t |
> (andmap positive? '(1 2 a)) |
positive?: expects argument of type <real number>; given 'a |
> (andmap positive? '(1 -2 a)) |
#f |
> (andmap + '(1 2 3) '(4 5 6)) |
9 |
(ormap proc lst ...+) → any |
proc : procedure? |
lst : list? |
the result is #f if every application of proc produces #f; and
the result is that of the first application of proc producing a value other than #f, in which case proc is not applied to later elements of the lsts; the application of proc to the last elements of the lsts is in tail position with respect to the ormap call.
If the lsts are empty, then #f is returned.
Examples: |
> (ormap eq? '(a b c) '(a b c)) |
#t |
> (ormap positive? '(1 2 a)) |
#t |
> (ormap + '(1 2 3) '(4 5 6)) |
5 |
(for-each proc lst ...+) → void? |
proc : procedure? |
lst : list? |
Example: | ||||
| ||||
|
(foldl proc init lst ...+) → any/c |
proc : procedure? |
init : any/c |
lst : list? |
If foldl is called with n lists, then proc must take n+1 arguments. The extra argument is the combined return values so far. The proc is initially invoked with the first item of each list, and the final argument is init. In subsequent invocations of proc, the last argument is the return value from the previous invocation of proc. The input lsts are traversed from left to right, and the result of the whole foldl application is the result of the last application of proc. If the lsts are empty, the result is init.
Unlike foldr, foldl processes the lsts in constant space (plus the space for each call to proc).
Examples: | |||||
> (foldl cons '() '(1 2 3 4)) | |||||
'(4 3 2 1) | |||||
> (foldl + 0 '(1 2 3 4)) | |||||
10 | |||||
| |||||
-27 |
(foldr proc init lst ...+) → any/c |
proc : procedure? |
init : any/c |
lst : list? |
Examples: |
> (foldr cons '() '(1 2 3 4)) |
'(1 2 3 4) |
> (foldr (lambda (v l) (cons (add1 v) l)) '() '(1 2 3 4)) |
'(2 3 4 5) |
3.9.4 List Filtering
(filter pred lst) → list? |
pred : procedure? |
lst : list? |
Example: |
> (filter positive? '(1 -2 3 4 -5)) |
'(1 3 4) |
Example: |
> (remove 2 (list 1 2 3 2 4)) |
'(1 3 2 4) |
Example: |
> (remq* (list 1 2) (list 1 2 3 2 4 5 2)) |
'(3 4 5) |
| ||||||||||||||||||||||||||||
lst : list? | ||||||||||||||||||||||||||||
less-than? : (any/c any/c . -> . any/c) | ||||||||||||||||||||||||||||
extract-key : (any/c . -> . any/c) = (lambda (x) x) | ||||||||||||||||||||||||||||
cache-keys? : boolean? = #f |
The sort is stable; if two elements of lst are “equal” (i.e., proc does not return a true value when given the pair in either order), then the elements preserve their relative order from lst in the output list. To preserve this guarantee, use sort with a strict comparison functions (e.g., < or string<?; not <= or string<=?).
The #:key argument extract-key is used to extract a key value for comparison from each list element. That is, the full comparison procedure is essentially
(lambda (x y) |
(less-than? (extract-key x) (extract-key y))) |
By default, extract-key is applied to two list elements for every comparison, but if cache-keys? is true, then the extract-key function is used exactly once for each list item. Supply a true value for cache-keys? when extract-key is an expensive operation; for example, if file-or-directory-modify-seconds is used to extract a timestamp for every file in a list, then cache-keys? should be #t to minimize file-system calls, but if extract-key is car, then cache-keys? should be #f. As another example, providing extract-key as (lambda (x) (random)) and #t for cache-keys? effectively shuffles the list.
Examples: | ||
> (sort '(1 3 4 2) <) | ||
'(1 2 3 4) | ||
> (sort '("aardvark" "dingo" "cow" "bear") string<?) | ||
'("aardvark" "bear" "cow" "dingo") | ||
| ||
'(("aardvark") ("bear") ("cow") ("dingo")) |
3.9.5 List Searching
Examples: |
> (member 2 (list 1 2 3 4)) |
'(2 3 4) |
> (member 9 (list 1 2 3 4)) |
#f |
(memf proc lst) → (or/c list? #f) |
proc : procedure? |
lst : list? |
Example: | |||
| |||
'(10 11) |
(findf proc lst) → any/c |
proc : procedure? |
lst : list? |
Examples: |
> (assoc 3 (list (list 1 2) (list 3 4) (list 5 6))) |
'(3 4) |
> (assoc 9 (list (list 1 2) (list 3 4) (list 5 6))) |
#f |
(assf proc lst) → (or/c list? #f) |
proc : procedure? |
lst : list? |
3.9.6 Pair Accessor Shorthands
Example: |
> (caar '((1 2) 3 4)) |
1 |
Example: |
> (cadr '((1 2) 3 4)) |
3 |
Example: |
> (cdar '((7 6 5 4 3 2 1) 8 9)) |
'(6 5 4 3 2 1) |
Example: |
> (cddr '(2 1)) |
'() |
Example: |
> (caaar '(((6 5 4 3 2 1) 7) 8 9)) |
6 |
Example: |
> (caadr '(9 (7 6 5 4 3 2 1) 8)) |
7 |
Example: |
> (cadar '((7 6 5 4 3 2 1) 8 9)) |
6 |
Example: |
> (caddr '(3 2 1)) |
1 |
Example: |
> (cdaar '(((6 5 4 3 2 1) 7) 8 9)) |
'(5 4 3 2 1) |
Example: |
> (cdadr '(9 (7 6 5 4 3 2 1) 8)) |
'(6 5 4 3 2 1) |
Example: |
> (cddar '((7 6 5 4 3 2 1) 8 9)) |
'(5 4 3 2 1) |
Example: |
> (cdddr '(3 2 1)) |
'() |
Example: |
> (caaaar '((((5 4 3 2 1) 6) 7) 8 9)) |
5 |
Example: |
> (caaadr '(9 ((6 5 4 3 2 1) 7) 8)) |
6 |
Example: |
> (caadar '((7 (5 4 3 2 1) 6) 8 9)) |
5 |
Example: |
> (caaddr '(9 8 (6 5 4 3 2 1) 7)) |
6 |
Example: |
> (cadaar '(((6 5 4 3 2 1) 7) 8 9)) |
5 |
Example: |
> (cadadr '(9 (7 6 5 4 3 2 1) 8)) |
6 |
Example: |
> (caddar '((7 6 5 4 3 2 1) 8 9)) |
5 |
Example: |
> (cadddr '(4 3 2 1)) |
1 |
Example: |
> (cdaaar '((((5 4 3 2 1) 6) 7) 8 9)) |
'(4 3 2 1) |
Example: |
> (cdaadr '(9 ((6 5 4 3 2 1) 7) 8)) |
'(5 4 3 2 1) |
Example: |
> (cdadar '((7 (5 4 3 2 1) 6) 8 9)) |
'(4 3 2 1) |
Example: |
> (cdaddr '(9 8 (6 5 4 3 2 1) 7)) |
'(5 4 3 2 1) |
Example: |
> (cddaar '(((6 5 4 3 2 1) 7) 8 9)) |
'(4 3 2 1) |
Example: |
> (cddadr '(9 (7 6 5 4 3 2 1) 8)) |
'(5 4 3 2 1) |
Example: |
> (cdddar '((7 6 5 4 3 2 1) 8 9)) |
'(4 3 2 1) |
Example: |
> (cddddr '(4 3 2 1)) |
'() |
3.9.7 Additional List Functions and Synonyms
Example: |
> (cons? '(1 2)) |
#t |
Example: |
> (first '(1 2 3 4 5 6 7 8 9 10)) |
1 |
Example: |
> (rest '(1 2 3 4 5 6 7 8 9 10)) |
'(2 3 4 5 6 7 8 9 10) |
Example: |
> (second '(1 2 3 4 5 6 7 8 9 10)) |
2 |
Example: |
> (third '(1 2 3 4 5 6 7 8 9 10)) |
3 |
Example: |
> (fourth '(1 2 3 4 5 6 7 8 9 10)) |
4 |
Example: |
> (fifth '(1 2 3 4 5 6 7 8 9 10)) |
5 |
Example: |
> (sixth '(1 2 3 4 5 6 7 8 9 10)) |
6 |
Example: |
> (seventh '(1 2 3 4 5 6 7 8 9 10)) |
7 |
Example: |
> (eighth '(1 2 3 4 5 6 7 8 9 10)) |
8 |
Example: |
> (ninth '(1 2 3 4 5 6 7 8 9 10)) |
9 |
Example: |
> (tenth '(1 2 3 4 5 6 7 8 9 10)) |
10 |
Example: |
> (last '(1 2 3 4 5 6 7 8 9 10)) |
10 |
Example: |
> (last-pair '(1 2 3 4)) |
'(4) |
(make-list k v) → list? |
k : exact-nonnegative-integer? |
v : any? |
Example: |
> (make-list 7 'foo) |
'(foo foo foo foo foo foo foo) |
(take lst pos) → list? |
lst : any/c |
pos : exact-nonnegative-integer? |
The lst argument need not actually be a list; lst must merely start with a chain of at least pos pairs.
Examples: |
> (take '(1 2 3 4) 2) |
'(1 2) |
> (take 'non-list 0) |
'() |
(drop lst pos) → any/c |
lst : any/c |
pos : exact-nonnegative-integer? |
| ||||||||
lst : any/c | ||||||||
pos : exact-nonnegative-integer? |
(values (take lst pos) (drop lst pos))
except that it can be faster.
(take-right lst pos) → any/c |
lst : any/c |
pos : exact-nonnegative-integer? |
The lst argument need not actually be a list; lst must merely end with a chain of at least pos pairs.
Examples: |
> (take-right '(1 2 3 4) 2) |
'(3 4) |
> (take-right 'non-list 0) |
'non-list |
(drop-right lst pos) → list? |
lst : any/c |
pos : exact-nonnegative-integer? |
The lst argument need not actually be a list; lst must merely end with a chain of at least pos pairs.
Examples: |
> (drop-right '(1 2 3 4) 2) |
'(1 2) |
> (drop-right 'non-list 0) |
'() |
| ||||||||
lst : any/c | ||||||||
pos : exact-nonnegative-integer? |
(values (drop-right lst pos) (take-right lst pos))
except that it can be faster.
Examples: |
> (split-at-right '(1 2 3 4 5 6) 3) |
'(1 2 3) |
'(4 5 6) |
> (split-at-right '(1 2 3 4 5 6) 4) |
'(1 2) |
'(3 4 5 6) |
(add-between lst v) → list? |
lst : list? |
v : any/c |
Examples: |
> (add-between '(x y z) 'or) |
'(x or y or z) |
> (add-between '(x) 'or) |
'(x) |
(append* lst ... lsts) → list? |
lst : list? |
lsts : (listof list?) |
(append* lst ... lsts) → any/c |
lst : list? |
lsts : list? |
Examples: | ||
> (append* '(a) '(b) '((c) (d))) | ||
'(a b c d) | ||
| ||
'("Alpha" ", " "Beta" ", " "Gamma") |
Examples: |
> (flatten '((a) b (c (d) . e) ())) |
'(a b c d e) |
> (flatten 'a) |
'(a) |
| |||||||||||||||||||||
lst : list? | |||||||||||||||||||||
same? : (any/c any/c . -> . any/c) = equal? | |||||||||||||||||||||
extract-key : (any/c . -> . any/c) = (lambda (x) x) |
The #:key argument extract-key is used to extract a key value from each list element, so two items are considered equal if (same? (extract-key x) (extract-key y)) is true.
Examples: |
> (remove-duplicates '(a b b a)) |
'(a b) |
> (remove-duplicates '(1 2 1.0 0)) |
'(1 2 1.0 0) |
> (remove-duplicates '(1 2 1.0 0) =) |
'(1 2 0) |
(filter-map proc lst ...+) → list? |
proc : procedure? |
lst : list? |
Example: |
> (filter-map (lambda (x) (and (positive? x) x)) '(1 2 3 -2 8)) |
'(1 2 3 8) |
(count proc lst ...+) → exact-nonnegative-integer? |
proc : procedure? |
lst : list? |
Example: |
> (count positive? '(1 -1 2 3 -2 5)) |
4 |
| ||||||||
pred : procedure? | ||||||||
lst : list? |
The result is the same as
(values (filter pred lst) (filter (negate pred) lst))
but pred is applied to each item in lst only once.
Example: |
> (partition even? '(1 2 3 4 5 6)) |
'(2 4 6) |
'(1 3 5) |
(append-map proc lst ...+) → list? |
proc : procedure? |
lst : list? |
Example: |
> (append-map vector->list '(#(1) #(2 3) #(4))) |
'(1 2 3 4) |
Example: |
> (filter-not even? '(1 2 3 4 5 6)) |
'(1 3 5) |
Examples: |
> (argmin car '((3 pears) (1 banana) (2 apples))) |
'(1 banana) |
> (argmin car '((1 banana) (1 orange))) |
'(1 banana) |
Examples: |
> (argmax car '((3 pears) (1 banana) (2 apples))) |
'(3 pears) |
> (argmax car '((3 pears) (3 oranges))) |
'(3 pears) |
3.9.8 Immutable Cyclic Data
(make-reader-graph v) → any/c |
v : any/c |
Since the copied vales can be immutable, and since the copy is also immutable, make-reader-graph can create cycles involving only immutable pairs, vectors, boxes, and hash tables.
Only the following kinds of values are copied and traversed to detect placeholders:
pairs
vectors, both mutable and immutable
boxes, both mutable and immutable
hash tables, both mutable and immutable
instances of a prefab structure type
placeholders created by make-placeholder and make-hash-placeholder
Due to these restrictions, make-reader-graph creates exactly the same sort of cyclic values as read.
Example: | ||||
| ||||
#0= '(1 . #0#) |
(placeholder? v) → boolean? |
v : any/c |
(make-placeholder v) → placeholder? |
v : any/c |
(placeholder-set! ph datum) → void? |
ph : placeholder? |
datum : any/c |
(placeholder-get ph) → any/c |
ph : placeholder? |
(hash-placeholder? v) → boolean? |
v : any/c |
(make-hash-placeholder assocs) → hash-placeholder? |
assocs : (listof pair?) |
(make-hasheq-placeholder assocs) → hash-placeholder? |
assocs : (listof pair?) |