I wanted to split a list into 2 parts, as per the chosen size, first the size and then the list. Example:
(split 3'(1 3 5 7 9))
(defun split (list count) (values (subseq list 0 count) (subseq list count)))
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It only takes a minute to sign up.Sign up to join this community
First, as already noted in a comment, the first argument of the function is the list, and the second is the number of elements. So in the examples below I assume that this is what you want.
Then, you do not specify if the the two returned values must be a copy of the original list or can (or must) share at least part of the elements of the original list. This is an important aspect of the meaning of the “split” operator.
If we want two obtain two fresh lists from the original one, then your solution is the best possible. This is because
subseq always make a copy of the subsequences of the original list. Another advantage of your solution is that it works for any sequence, not only for lists.
If we dont want to modify the original list, but we allow (or require) the sharing of the second sublist with the original one, then here is a possible solution with the use of the function
nthcdr that returns the tail of a list:
(defun split2 (list count) (values (subseq list 0 count) (nthcdr count list)))
Finally, if we require a “physical” split of the original list, so that it is modified, then we can use a third approach (note that in this case a count of 0 should not be allowed):
(defun split3 (list count) (let* ((last-element (nthcdr (1- count) list)) (second-sublist (cdr last-element))) (rplacd last-element nil) (values list second-sublist)))
Finally, note that in all the cases we do not check for the correctness of the input, which is an important aspect of a function like this. So, a check should be made before the main part of the function, taking the appropriate action if
count is less than 0 or greater than the length of the list. Note that is also a good practice to put a comment at the beginning of the function specifying its meaning.
So, for instance:
(defun split2 (list count) "split a list into two sublists, the first one with count elements. Returns a new first list, while the second sublist is part of the original one." (if (or (< count 0) (> count (length list))) (error "invalid count ~a in split" count) (values (subseq list 0 count) (nthcdr count list))))
Note that the efficiency of this last version is less than optimal since it must compute the length of the list.