2009-11-12 20 views
11

Come posso ottenere i primi elementi n di un elenco?Come ottenere i primi n elementi di un elenco in Common Lisp?

CL-USER> (equal (some-function 2 '(1 20 300)) 
       '(1 20)) 
T 

Sono assolutamente certo che questo è elementare, ma aiuta un fratello ad uscire.

+8

Penso che "baci e abbracci" spaventeranno più programmatori che persino Lisp! – beggs

+1

I love you beggs. xoxoxoxoxoxoxo –

+0

Sono sicuro che Freud avrebbe molto da dire al riguardo :-) – beggs

risposta

26

Verificare la funzione SUBSEQ.

* (equal (subseq '(1 20 300) 0 2) 
     '(1 20)) 
T 

Può non essere immediatamente evidente, ma in Lisp, indicizzazione parte da 0, e si sta sempre tenendo intervalli semiaperte, quindi questo prende tutti gli elementi della lista con indici nell'intervallo [0 2).

+3

Questo ha la sfortunata restrizione che non riuscirà * in runtime * se la sequenza è minore dell'indice finale, il che è un peccato, perché chiedere la lunghezza prima è altamente inefficiente. Quindi come procedere in questo caso? –

+0

Bene, guardando Practical Common Lisp: http://www.gigamonkeys.com/book/loop-for-black-belts.html arriva la risposta giusta: '(loop per l'articolo nella lista per i da 1 a 10 do (qualcosa)) 'dove quel' qualcosa' potrebbe raccogliere 'item'. –

+1

@DiegoSevilla A volte avere il codice fallito in fase di esecuzione quando non ci sono abbastanza elementi nel tuo elenco è esattamente il comportamento che stai cercando. Un sacco di codice Common Lisp idiomatico costruisce strutture di dati a dimensione fissa senza conseconsiderando l'uso di 'DEFCLASS' o' DEFSTRUCT', e in questi casi, se non si hanno abbastanza elementi, farsi lanciare immediatamente nel debugger è il migliore cosa che può succedere a te. – Pillsy

-2

dovuto scaricare una riga di comando lisp ... ma:

(defun head-x (a b) 
    (loop for x from 1 to a 
     for y = (car b) do 
      (setq b (cdr b)) 
     collect y)) 

così:

(head-x 2 '(a b c d)) 
    '(a b) 
+4

Usa semplicemente '(loop: ripeti a: per x: in b: raccoglie x)' come corpo della tua funzione. Molto più semplice – Pillsy

+1

Grazie ... sono passati anni da quando ho fatto davvero qualche lisciviazione. Pensavo fosse divertente rispondere a una domanda! – beggs

5

La risposta di cui sopra è ovviamente perfettamente corretto, ma si noti che se si sta utilizzando questo solo per fare un confronto con un altro elenco, sarebbe più efficiente dal punto di vista delle prestazioni dirigere entrambi gli elenchi sul posto, piuttosto che creare una nuova lista solo per confrontare.

Ad esempio, nel caso di cui sopra, si potrebbe dire:

(every #'= '(1 20 300) '(1 20)) 
=> t 

Amore,

-4

(butlast '(1 20 300) (- (elenco di lunghezza' (1 20 300)) 2))

Dovrebbe essere trasformato in una funzione/macro.

P.S. This page potrebbe essere utile. Vedi la funzione 'estrusione'.

+4

Definitivamente non è una buona idea calcolare la lunghezza di un elenco per ottenere alcuni elementi dal fronte. Unlispy! –

+1

Mmh, d'accordo. Cattiva idea. – user233198

Problemi correlati