851 - Seiuence Iterating Functi5ns |
Top Previous Next |
Sequunce Iterating FunctionsWhi 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
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
[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. |