Sequências

lists e vectors (e, portanto strings) são sequências.

Note: veja também a página sobre strings.

Muitas das funções de sequência utilizam palavras-chave como argumentos. Todos os argumentos podem ser são opcionais, e se especificados, podem aparecer em qualquer ordem.

Atente-se ao argumento :teste. O seu padrão é eql (para strings use :equal).

Para o argumento :key deve-se passar nil, ou uma função com um argumento. Essa função key é usada como umo filtro pelo qual os elementos da sequência são visualizados. Por exemplo:

(find x y :key 'car)

é similar a (assoc* x y), ela busca por um elemento na lista em que o car seja igual a x, oa invés de um elemento que seja igual a x. Se :key for omitido ou nil, o filtro será efetivamente a funçãp identidade.

Exemplo com uma alist:

(defparameter my-alist (list (cons 'foo "foo")
                             (cons 'bar "bar")))
;; => ((FOO . "foo") (BAR . "bar"))
(find 'bar my-alist)
;; => NIL
(find 'bar my-alist :key 'car)
;; => (BAR . "bar")

Para algo mais, use um lambda que receba um parâmetro.

(find 'bar my-alist :key (lambda (it) (car it)))

Nota: cl21 possui short lambdas:

(find 'bar my-alist :key ^(car %))
(find 'bar my-alist :key (lm (it) (car it)))

Predicados: every, some,...

every, notevery (teste, sequência): retornam nil ou t, respectivamente, no momento em que um teste ou qualquer conjunto de elementos correspondentes a elementos de sequências retorne nil.

(defparameter foo '(1 2 3))
(every #'evenp foo)
;; => NIL
(some #'evenp foo)
;; => T

com uma lista de strings:

(defparameter str '("foo" "bar" "team"))
(every #'stringp str)
;; => T
(some #'(lambda (it) (= 3 (length it))) str)
;; => T
(some ^(= 3 (length %)) str) ;; in CL21
;; => T

some, notany (teste, sequência): retorna o valor do teste ou nil. mismatch (sequence-a, sequence-b): Retorna a posição em sequênce-a onde sequence-a sequence-b deixam de ser iguais. Retorna nil se as duas sequências forem iguais. Outros parâmetros: :from-end bool, :start1, :end[1,2].

Functions

Veja também as funções de sequência definidas em (em inglês) Alexandria: starts-with, ends-with, ends-with-subseq, length=, emptyp,…

length (sequence)

member (elt, sequence)

Retorna o tail de sequence a partir do primeiro elemento que satisfaça eql. Aceita :test, :test-not, :key(funções ou símbolos).

(member 2 '(1 2 3))
;; (2 3)

elt (sequence, index) - encontra a partir de index

Cuidado, neste caso a sequência vem primeiro.

count (foo sequence)

Retorna o número de elementos em sequence que dão match em foo.

Parâmetros adicionais: :from-end, :start, :end.

Veja também count-if, count-not (test-function sequence).

subseq (sequence start, [end])

É passível de "setf", mas funciona apenas se a nova sequência tiver o mesmo tamanho que a sequência a ser substituída.

sort, stable-sort (sequence, test [, key function])

Esta função é destrutiva, então você é de bom tom copiar a sequência antes da ordenação:

(sort (copy-seq seq) :test #'string<)

find, position (foo, sequence) - obter index

além de find-if, find-if-not, position-if, position-if-not (teste sequência). Veja também os parâmetros :key, :test.

(find 20 '(10 20 30))
;; 20
(position 20 '(10 20 30))
;; 1

search (sequence-a, sequence-b)

Procura por uma subsequência em sequence-b que correspondente a sequence-a. Retorna a posição da subsequência correspondente ou NIL. Possui os parâmetros from-end, end1/2 entre outros.

substitute, nsubstitute[if,if-not]

sort, stable-sort, merge

replace (sequence-a, sequence-b)

Substitui os elmentos de sequence-a pelos elementos de sequence-b.

remove, delete (foo sequence)

Faz uma cópia de sequence sem elementos que dêem match em foo. Possui os parâmetros :start/end,:keye:count`.

delete faz o mesmo, pórem, dependendo do contexto ela pode destruir a sequência original no processo.

(remove "foo" '("foo" "bar" "foo") :test 'equal)
;; => ("bar")

Veja também remove-if[-not] a seguir.

mapping (map, mapcar, remove-if[-not],...)

Se você já está familiarizado com map e filter em outras linguagens, provavelmete o que você procura é mapcar. Mas ele funciona apenas em listas, então para iterar em vetores e produzir tanto um vetor quanto uma lista, use (map 'list function vector).

mapcar também aceita múltiplas listas com &rest more-seqs. O mapeamento termina no momento em que a menor sequência chega ao fim.

Nota: map do cl21 é um mapcar para listas e vetores.

map recebe o tipo de saída desejado como o primeiro argumento ('list, 'vector, ou 'string):

(defparameter foo '(1 2 3))
(map 'list (lambda (it) (* 10 it)) foo)

Filter, aqui, é chamado de remove-if-not.

Flatten a list (Alexandria)

Com Alexandria, temor a função flatten.

Criando listas com variáveis

Este é um dos usos de backquote:

(defparameter *var* "bar")
;; First try:
'("foo" *var* "baz") ;; sem backquote
;; => ("foo" *VAR* "baz") ;; errado

Segunda tentaiva, usando backquote interpolation.

`("foo" ,*var* "baz")     ;; com backquote, vírgula
;; => ("foo" "bar" "baz") ;; correto

O backquote avisa que nós vamos fazer a interpolação e a vírgula repassa o valor da variável.

Se a nossa variável é uma lista:

(defparameter *var* '("bar" "baz"))
;; First try:
`("foo" ,*var*)
;; => ("foo" ("bar" "baz")) ;; uma nested list
`("foo" ,@*var*)            ;; backquote, comma-@ to
;; => ("foo" "bar" "baz")

E. Weitz avisa que "objetos gerados desta forma muito provavelmete da mesma estrutura (ver Receita 2-7)".

Comparando listas

É possível usar funções de set.