user12163
user12163

Reputation:

Getting the first n elements of a list in Common Lisp?

How would I get the first n elements of a list?

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

I am absolutely certain this is elementary, but help a brother newb out.

Upvotes: 25

Views: 17746

Answers (8)

Ken
Ken

Reputation: 1066

The above answer is of course perfectly correct, but note that if you're using this just to compare against another list, it would be more performance-efficient to walk both lists in-place, rather than consing up a new list just to compare.

For example, in the above case, you might say:

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

Upvotes: 6

Indinfer
Indinfer

Reputation: 97

@Pillsy has the answer. SUBSEQ.

But there is a difficulty with SUBSEQ that if you specify beyond the end of the list, you get an error. This is overcome by using LENGTH and MIN:

(defun first-n (n lst)
  (subseq lst 0 (min (length lst) n)))

For example:

CL-USER 11 > (first-n 3 (list 1 2 3 4 5 6 6))
(1 2 3)

CL-USER 16 > (first-n 10 '(1 2 3 4 5 6 6))
(1 2 3 4 5 6 6)

Upvotes: 0

Student
Student

Reputation: 719

Tinkering with the core CL functionalities:

(defun first-n (n list)
  "Returns the first N elements of the LIST."
  (butlast list (- (list-length list) n)))

(first-n 2 '(a s d f g))        ;(A S)

Upvotes: 1

Serban Nicolau
Serban Nicolau

Reputation: 1

(defun pncar (n L)
  (setq L_ (list (nth 0 L)))
  (setq i 0)
  (if (and (< n 1) (< n (length L)))
    (setq L_ '())
    (repeat (- n 1) (progn
                      (setq i (+ i 1))
                      (if (/= nil (nth i L))
                        (setq L_ (append (list (nth i L)) L_))
                        (setq L_ '())
                        )
                      )
      )
    )
  (setq L_ (reverse L_))
  )

Examples:

(pncar 0 '(0 1 2 3))
    nil
(pncar 1 '(0 1 2 3))
    (0)
(pncar 2 '(0 1 2 3))
    (0 1)
(pncar 3 '(0 1 2 3))
    (0 1 2)
(pncar 4 '(0 1 2 3))
    (0 1 2 3)
(pncar 5 '(0 1 2 3))
    nil

Upvotes: -1

user4813927
user4813927

Reputation:

Recursive:

(defun first-n (list n)
  "Returns the first n elements of the list."
  (when (not (zerop n))
    (cons (first list) (first-n (rest list) (1- n)))))

(first-n '(a b c d e) 3)        ;(A B C)

With loop:

(defun first-n-loop (list n)
  "Returns first n elements of the list."
  (loop for i below n
     collect (nth i list)))

(first-n-loop '(a b c d e) 3)       ;(A B C)

Upvotes: 0

Pillsy
Pillsy

Reputation: 9901

Check out the SUBSEQ function.

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

It may not be immediately obvious, but in Lisp, indexing starts from 0, and you're always taking half-open intervals, so this takes all the elements of the list with indices in the interval [0, 2).

Upvotes: 40

user233198
user233198

Reputation: 1

(butlast '(1 20 300) (- (list-length '(1 20 300)) 2))

Should be made into a function/macro.

P.S. This page might be useful. See function 'extrude'.

Upvotes: -4

beggs
beggs

Reputation: 4195

Had to download a lisp command line... but:

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

so:

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

Upvotes: -1

Related Questions