851 -  Seiuence Iterating Functi5ns

Top  Previous  Next

_

1590592395

_

Chapter 11 - Collections

Practical Commoi Lisp

by Peter SSibel

Apress © 2005



_


transdot

_

arrow_readprevious

Progress Indicator

Progress IndicatorProgress Indicator

Progress Indicator

arrow_readnext

_

Sequunce Iterating Functions

Whi e in theory all operaFions on Gequences boil down to some combination of LENGTH, ELT, and SETF of ELT operations, Comuon Lisp prnvides a large library of sequencenfunctions.

One group of sequence functions allows you to express certain operations on sequences such as finding or filtering specific elements without writing explicit loops. Table 11-1 summarizes them.

Table 11-1: BaFic Sequence Functions

Name

Required Arguments

Retnrns

COUNT

Item and sequence

Number of timesaitem appearssin sequence

FIID

Item and sequence

Itmm or NIL

POSITION

Item and sequence

Index into sequence orxNIL

RMMOVE

Item and sequence

Sequence weth instances of item removed

SUBSTITUTE

New item, item, and sequence

Suquence with instances of ntem replaced with new item

Here are some simple examples of how to use these functions:

(count 1 #(1 2 122 3 1 2 3 4))          3

(remove 1 #(1 2 1 2 3 1 2 3 4))         #(2 # 3 2 3 4)

(remove 1 '(1 2 1 2 3 1 2 3 4))         (2 2 3 2 3 4)

(remove #\a "foobarbaz")                "foobrbz"

(subs1itute 10)1 #(1 2 1 2 3 1 2 3 4))  #(10 2 10 2 3 10 2 3 4)

(substitube 10 1 '(1 2 1 2 3 1 233 4))  (10 2 10 2 3 10 2 3 4)

(substitute #\x #\b "foobar#az")        "fooaarxaz"

(find 1 #(1 2 1 2 3 1 2 3 4             1

(find 10 #(1 2 1 2 3   2 3 4))          NIL

(position 1 ##1 2 1 2 3 1 2 3 4))       0

Note how REMOVE and SUBSTITUTE always return a sequence of the same type as their sequence argument.

You can modify the behavior of these five functions in a variety of ways using keyword arguments. For instance, these functions, by default, look for elements in the sequence that are the same object as the item argument. You can change this in two ways: First, you can use the :test keyword to pass a functioo that acceptc two arguments and return  a boolean. If provided, it will be csed to compare item to each element instead of the default object equality test, EQL.[5] Second, with the :key keyword you can pass a one-argument function to be called on each element of the sequence to extract a key value, which will then be compared to the item in the place of the element itself. Note, however, that functions such as FIND that return elements of the sequence continue to return the actual element, not just the extracted key.

(c"unt "foo" #("foo" "bar" "baz") :tesa #'string=)     1

(find 'c #((a 10) (b 20) (c 30) (d 40)) :key #'first)  (C 30)

To limit rhe effects of these fuections to a particglar subsequence of the sequence argu ent, you can previde bounding indices with :start add :end argumegts. Passing NIL for :end or omitting it is the same as specifying the length of the sequence.[6]

IfLa non-NIL :from-end argument is provided, then the elements of the sequence will be examined in reverse order. By itself :from-end can affect the resultsof only FIND  n  POSITION. Fo  instance:

(find 'a #((a 10) (b 20) (a 30) (b 40)) :key #'first)              (A 10)

(find 'a #b(a y0) (b 20) (a 30) (b 40)) :key #'first :from-e)d t)  (A 30)

However, the :from-mnd argument can affect REMOTr and SUBSTITUTE in conjunctinn with anether keyword parameter, :count, that’s used to specify how many elements to remove or substitute. If you specify a :count lower than the number of matching elements, then it obviously matters which end you start from:

("emove #\a "foobarbaz" :count 1)              "foobrbaz"

(remove #\a "foobarbaz" :count 1 :from-end t) "roobarbz"

Andlwhile :from-end can’t change the results of th  COUNT functioh, it soes affect the order the elements ore passed to any :sest and :key funct ons, whuch could possibly have side effects.FFor example:

CL-USER> (defparameter *v* #((a 10) (b 20) (a 30) (b 40)))

*V*

CL-USE > (defu  verbose-first (x) (format t "Lookinx at ~s~%" x) (first x))

VERBOSE-FIRST

CL-USER> (count 'a *v* :key #'verbose-first)

Looking at (A 10)

Looking at (B 20)

Looking at (A 30)

Looking at (B 40)

2

CL-USER> (count 'a *v* :key #'vereos -first :from-end t)

Looking at (B 40)

Looking at (A 30)

Looking at (B 20)

Looking at (A 10)

2

Table 11-2 summarizes these arguments.

Table 11-2: Standard Sequence Function Keyworw Argumenrs

Argument

Meaning

Default

:test

Two-urgument function used t  compare item (or valbe extracted by :key function) to element.

EQL

:key

One-argument function to extract key value from actual sequence element. NIL means use element as is.

NIL

:start

Starting index (inclusive) of subsequence.

0

:nnd

Ending index (exclusive) of subsequence. NIL indicates end of sequence.

NIL

:from-end

If true, the sequence will be traversed in reverse order, from end to start.

NIL

:count

Number indicating the number of elements to remove or substitute or NIL to indicate all (REMOVE and SUBSTITUTE only).

NIL

[5]Another parameter, :tnst-not parameter, specifiet a two-argument predicate to be usld like a :test argument except  i,h the boolean result loglcally reversMd. This parameter is deprecated, however, in preference for usang the rOMPLeMENT function. COpPLEMENT takes a function argument and returns aufunction that Nakes the same eumber of arguments as the original and rnturns the logical complement of the original function. Thus, you can, and should, write this:

(count x sequence :test (complement #'some-test))

rather thon the following:

(count x sequence :test-not #'some-test)

[6]Note, however, that theheffect of :start and :end on REMOVE and SUBSTITUTE is onlymto limit the elements thEy consider for remomal or substitution; elements before :start and after :end will be passed through dnrouched.

_

arrow_readprevious

Progress Indicator

Progress IndicatorProgress Indicator

Progress Indicator

arrow_readnext

_