Accessing List Elements¶
In addition to the basic procedures
cdr Scheme provides a number of higher-level ways to access the different list items individually.
Number of Elements of a List¶
Often it is necessary to know the length, respectively the number of elements of a list. This is determined by the
guile> (length '(a b c d)) 4
Note that this expects a proper list to work, applying
length to an improper list or a pair will result in an error.
It is possible to access the n-th element of a list using the
list-ref procedure, which is passed first the list and then the requested index as arguments:
guile> (list-ref '(a b c d) 3) d guile> (list-ref '(a b c d) 4) standard input:7:1: In procedure list-ref in expression (list-ref (quote #) 4): standard input:7:1: Argument 2 out of range: 4 ABORT: (out-of-range)
There are two things to note about this: The index is “zero-based”, that means that the fourth list entry will have the index 3. And it will result in an error when you try to access a non-existent index as in the second example. The highest possible index is one lower than the length of the list. So if the list has four elements as in our example the highest index is 3.
In order to avoid this kind of error you can make use of the
length procedure, once you have learned about conditionals and iteration constructs later in this book. As an example that works already now you can use it to access the last element of a list:
guile>(define lst '(1 2 3 4)) guile>lst (1 2 3 4) guile> (list-ref lst (- (length lst) 1)) 4
In this example we calculate the index of the last element by subtracting one from the length of the list.
Guile defines a number of convenience accessor methods to retrieve list elements by their position specified in English words instead of the number:
guile> (define lst '(1 2 3 4 5)) guile> (first lst) 1 guile> (second lst) 2 guile> (fifth lst) 5
Such procedures are defined for the first ten elements of a list (i.e.
tenth). Note that “first” here really means the first, so
(first lst) is equivalent to
(list-ref lst 0).
In addition there is the
last procedure that always retrieves the last element of the list, regardless of its index. As
list-ref these functions implictly retrieve the
car of an element. So unlike accessing elements through the
cdr functions it is not necessary anymore to explicitly unfold the value using
car. But unexpected results may occur when the list is an improper list. Please investigate the result of the following expressions yourself - if you have difficulties with that please refer to the explanation about list structure.
guile> (last '(1 2 3 4 5)) 5 guile> (last '(1 2 3 4 . 5)) 4
Accessing Parts of a List¶
Sometimes it's necessary to retrieve parts of a list, for example all elements starting with the third or up to the fourth. For this the procedures
list-head are provided.
guile>(define lst '(1 2 3 4 5 6)) (list-tail lst 2) (3 4 5 6)
list-tail takes the list and the starting index as arguments. So in this example the list elements starting with index 2 are retrieved. Colloquially one can also say the arguments specifies the number of elements to be skipped.
guile>(define lst '(1 2 3 4 5 6)) (list-head lst 2) (1 2)
list-head the index argument specifies the index to which but not including the list elements are retrieved. However, again this can colloquially be expressed much clearer as the “number of retrieved elements”.
If an actual sub-list is required the procedures can be stacked/nested:
guile> (list-head (list-tail lst 2) 2) (3 4)
list-tail expression is evaluated, resulting in the list
(3 4 5 6), then this is passed to