DO to DOTIMES
[jscl.git] / src / list.lisp
index 9cb8e45..8efb95a 100644 (file)
     (when (eql tail object)
       (return-from tailp t))))
 
+(defun make-list (size &key (initial-element nil))
+  "Create a list of size `size` of `initial-element`s."
+  (when (< size 0)
+    (error "Size must be non-negative"))
+  (let ((newlist))
+    (dotimes (i size newlist)
+      (push initial-element newlist))))
+
 (defun map1 (func list)
   (with-collect
     (while list
     (setq x (cdr x)))
   x)
 
-(defun butlast (x)
-  (and (consp (cdr x))
-       (cons (car x) (butlast (cdr x)))))
-
-(defun member (x list &key key (test #'eql testp) (test-not #'eql test-not-p)) 
+(defun butlast (x &optional (n 1))
+  "Returns x, less the n last elements in the list."
+  (cond
+      ;; trivial optimizations
+    ((not x) x)
+    ((zerop n) x)
+
+    ;; Base case
+    ((= n 1)
+     (and (consp (cdr x))
+          (cons (car x)
+                (butlast (cdr x) n))))
+    ;; O(n * (length x)) butlast for n > 1.
+    (t
+     (let ((temp x))
+       (do
+        ((iter 0))
+        ;; quit when we reach the top or we ran out
+        ((or (= iter n)
+             (not temp)))
+         (setf temp (butlast temp 1))
+         (incf iter))
+       temp))))
+
+(defun member (x list &key key (test #'eql testp) (test-not #'eql test-not-p))
   (while list
     (when (satisfies-test-p x (car list) :key key :test test :testp testp
                             :test-not test-not :test-not-p test-not-p)