I have a list like this:
(4 5 6 3 12 22 4 4 55 43 1 4 0)
and want an output like this:
((4 5 6) (3) (12 22) (4) (4 55) (43) (1 4) (0))
I think you can guess the order, it has an ascending order, I'm totally new with Lisp and need some help
Here is one possible solution in TXR Lisp:
(defun ascending-partitions (list)
(let ((indices (mappend (do if (>= #1 #2) (list #3))
list (cdr list) (range 1))))
(split list indices)))
We obtain the numeric index positions of the elements in the list which are not greater than their predecessors; then we use the split function to cut the list into pieces at these indices.
Calculating the indices is done by processing three lists through the mappend function: the original list, in parallel with that same list with the first element removed (cdr list), and an infinite list of incrementing integers starting at 1 produced by (range 1).
The do macro writes an anonymous function for us, in which the #1, #2 and #3 variables embedded in the expression are its three arguments, in that order. mappend call this function with successive triplets of values taken from the lists in parallel. Thus #1 takes values from list, #2 takes successive values from (cdr list) and #3 takes successive values from the list of integers. Whenever #1 is at least as large as its successor #2, we collect the positional index #3 into a one-element list. mappend catenates these together.
In contrast to this, we could write a more direct solution that requires more code, but makes better use of machine resources:
(defun ascending-partitions (list)
(let (partition output prev)
(each ((item list)) ;; use (dolist (item list) in Common Lisp
(when (and prev (<= item prev))
(when partition
(push (nreverse partition) output)
(set partition nil))) ;; use setf or setq in Common Lisp
(push item partition)
(set prev item)) ;; ditto
(when partition
(push (nreverse partition) output))
(nreverse output)))
Related
As mentioned here, I'm trying to teach myself lisp by implementing lodash.
I have basically no experience with lisp, so work that would be trivial in js is foreign to me.
For instance, I'm working on implementation of a _.chunk method, which in js takes an array and a size variable and 'chunks' the array by the size:
_.chunk(['a', 'b', 'c', 'd'], 2);
// => [['a', 'b'], ['c', 'd']]
_.chunk(['a', 'b', 'c', 'd'], 3);
// => [['a', 'b', 'c'], ['d']]
As somebody totally new to common lisp data types, I would assume that the analogous type would be a vector, not an array, is that correct?
Secondly, my way of solving this algorithmically would be to retain a length variable, and a pointer variable, and to grab a subset of the array/vector, [pointer to pointer + size], while pointer + size was < length, and then return [pointer to length] when that was no longer true, and incrementing pointer to pointer + size + 1 otherwise.
No idea how to implement this in lisp, here is my code so far.
(defun _.chunk (vector &optional (size 1 size-p))
(if (or (not size-p) (eq size 1))
vector
((let (
(array_length (array-total-size array))
(pointer)
)
???
))
)
)
For this implementation I would first write an idiomatic Common Lisp version of chunk that can be useful in a CL program (efficient, etc.), and then write a thin lodash layer that only wraps around those functions.
For example, I would first write a helper function to allow sharing storage with the chunked vector. A displaced array refers to another array but with an offset and different size. It may be useful to have chunks be only views of the original vector, so that they all share the same underlying storage array. It is not only a memory optimization: the behaviour is different when mutating either a chunk or the original vector, since any change in one is visible in the other. But as far as I know lodash is (was?) a pure functional language, so it makes sense to share some data if you don't mutate them. Some languages call those kind of indirect arrays "slices".
(defun slice (vector start end)
(make-array (- end start)
:element-type (array-element-type vector)
:displaced-to vector
:displaced-index-offset start))
So I would also make chunk-vector accept :start and :end parameters, as commonly done, along with sharedp which specifies if storage should be shared with the original vector:
(defun chunk-vector (size vector &key start end sharedp)
(check-type size (integer 1))
(loop
with slicer = (if sharedp #'slice #'subseq)
and low = (or start 0)
and high = (or end (length vector))
for s from low below high by size
for e from (+ low size) by size
collect (funcall slicer vector s (min e high))))
Note: I assume nil is a possible value for end that means the end of the vector, to mirror how subseq works. I do the same for start, because for those variables the nil value can be used without ambiguity to mean "default value". I could also have defined defaults in the lambda list, as done in tfb's answer.
Here are some tests:
(chunk-vector 3 #(0 1 2 3 4 5 6 7 8 9) :sharedp t)
(#(0 1 2) #(3 4 5) #(6 7 8) #(9))
(chunk-vector 2 #(0 1 2 3 4 5 6 7 8 9))
(#(0 1) #(2 3) #(4 5) #(6 7) #(8 9))
(chunk-vector 1 #(0 1 2 3 4 5 6 7 8 9))
(#(0) #(1) #(2) #(3) #(4) #(5) #(6) #(7) #(8) #(9))
Likewise, you could also define a chunk-list function and have the lodash chunck function dispatch to each specialized version based on the sequence type.
This can be done with CLOS, but since that is already demonstrated in another answer, I'll just define individual specialized functions.
Here is an implementation of chunk-list that is based on LDIFF.
I tried first mixing all cases in one function, but this becomes needlessly complex.
Here is first an unbounded chunk function:
(defun chunk-list/unbounded (size list)
(loop
for front = list then next
for next = (nthcdr size front)
collect (ldiff front next)
while next))
front is defined as initially list, then the current value of next at each step
next is the next chunk, computed using size; this plays nicely with lists that have not enough elements, since in that case nthcdr just returns the remaining elements.
A bit more complex case is required to handle the end argument, and for that we define the bounded version where there is also an additional upper-limit counter, that decreases by size at each step of iteration. It represents remaining number of elements to add, and is used along with size to compute (min size upper-limit), the size of the next chunk:
(defun chunk-list/bounded (size list upper-limit)
(loop
for front = list then next
for next = (nthcdr (min size upper-limit) front)
collect (ldiff front next)
do (decf upper-limit size)
while (and next (plusp upper-limit))))
Finally, chunk-list dispatches on both versions based on whether end is nil or not; the calls are inlined here (because we can):
(defun chunk-list (size list &key (start 0) end)
(declare (inline check-list/bounded check-list/simple))
(check-type size (integer 1))
(let ((list (nthcdr start list)))
(when list
(if end
(chunk-list/bounded size list (- end start))
(chunk-list/unbounded size list)))))
Some examples:
(chunk-list 3 '(1 2 3 4 5 6 7))
((1 2 3) (4 5 6) (7))
(chunk-list 29 '(1 2))
((1 2))
(chunk-list 2 (alexandria:iota 100 :start 0) :start 10 :end 20)
((10 11) (12 13) (14 15) (16 17) (18 19))
i would propose step-by step slicing iterating over the chunk index (since you can easily find out the total amount of chunks), using dotimes.
this could look something like the following:
(defun chunked (seq size)
(let* ((total (length seq))
(amount (ceiling total size))
(res (make-array amount :fill-pointer 0)))
(dotimes (i amount res)
(vector-push (subseq seq (* i size) (min (* (1+ i) size) total))
res))))
CL-USER> (chunked "abcdefgh" 3)
;; #("abc" "def" "gh")
CL-USER> (chunked #*00101 2)
;; #(#*00 #*10 #*1)
CL-USER> (chunked (list :a :b :c :d :e) 1)
;; #((:A) (:B) (:C) (:D) (:E))
CL-USER> (chunked (list :a :b :c :d :e) 4)
;; #((:A :B :C :D) (:E))
This is an addendum to coredump's answer, as well as referring to a comment by Kaz. Most of this is about style, which is always a matter of opinion and I do not claim my opinion is better than theirs: I just think it is interesting to talk about the choices as Lisp programming is very much about style choice, since the language is so flexible compared to most others. The last section ('extending') might be interesting however.
Argument order
The problem with a signature which is (size vector ...) is that size can't be optional. If you want it to be, it can't be the first argument to the function. Whether that outweighs the easy utility of partial-application libraries I don't know (however, in the 'do the right thing' spirit, if I wrote a partial application library it would allow you to specify which args it was currying, so this would not be a problem).
So if size needs to be optional then the argument order must be (vector size ...).
Further, since coredump's answer uses keyword arguments, I would make size be one as well as you almost never want to mix keyword & optional arguments. So that leads to a signature which would be (vector &key size start end sharedp), and I'd then write the actual function as
(defun chunk-vector (vector &key (size 1) (start 0) (end (length vector))
(sharedp nil))
(check-type size (integer 1))
(let ((slicer (if sharedp #'slice #'subseq)))
(loop for s from start below end by size
for e from (+ start size) by size
collect (funcall slicer thing s (min e end)))))
This slightly improves on coredump's version by defaulting the arguments in the arglist rather than later.
Extending chunk-vector
Pretty obviously you might want to chunk other kinds of things, such as lists, and pretty obviously the algorithm for chunking a list will be very different than that for chunking a vector, because you really do not want to repeatedly call subseq on a list.
Well, this is what CLOS is for. First of all we can define a generic chunk function:
(defgeneric chunk (thing &key)
;; in real life we might want to specify some of the keyword
;; arguments at the GF level, but we won't
)
And now define methods for classes we care about. Firstly the method to chunk vectors, which is pretty much the previous function:
(defmethod chunk ((thing vector) &key
(size 1) (start 0) (end (length thing)) (sharedp nil))
(check-type size (integer 1))
(let ((slicer (if sharedp #'slice #'subseq)))
(loop for s from start below end by size
for e from (+ start size) by size
collect (funcall slicer thing s (min e end)))))
And now, for instance, one to chunk lists. Note this may be buggy, and there may be better ways of doing this.
(defmethod chunk ((thing list) &key
(size 1) (start 0) (end nil endp) (sharedp nil))
;; This does not implemenent SHAREDP: this could only be useful for
;; the last chunk, and since you don't know if you could share a
;; chunk until you have already walked the list it did not seem
;; worth it. It may also be buggy in its handling of END.
(declare (ignorable sharedp))
(flet ((next (lt)
(nthcdr size lt))
(the-chunk (lt p)
(loop for c below (if endp (min size (- end p)) size)
for e in lt
do (print c)
collect e)))
(loop for tail on (nthcdr start thing) by #'next
for pos upfrom start by size
while (or (not endp) (< pos end))
collect (the-chunk tail pos))))
And of course you can now define methods on this function for other appropriate types.
The input could certainly be a vector (a vector is a 1-dimensional array). Lisp has a few more sensible options of how to represent the result: it could be a 2-dimensional array, a vector of vectors, or maybe even a list of vectors.
To get a 2-dimensional array:
(defun reshape-2d (column-count vector &optional padding-element)
(let* ((row-count (ceiling (length vector) column-count))
(array (make-array (list row-count column-count)
:initial-element padding-element)))
(loop :for i :below (length vector)
:do (setf (row-major-aref array i) (aref vector i)))
array))
To get a vector of vectors:
(defun chunkv (size vector)
(let ((vectors (make-array (ceiling (length vector) size))))
(loop :for i :below (length vector) :by size
:for j :below (length vectors)
:do (setf (aref vectors j) (subseq vector
i
(min (1- (length vector))
(+ i size)))))
vectors))
To get a list of vectors:
(defun chunkl (size vector)
(loop :for i :below (length vector) :by size
:collect (subseq vector
i
(min (1- (length vector))
(+ i size)))))
This last version could actually chunk any sequence because it only uses sequence functions.
(for judges ([judge1 judge2 judge3 judge4 judge5 judge6 judge7 judge8])
(define i 0)
(define j 1)
(cond [(< judges[i] judges[j])
(cond [(equal? judges[j] judges(length))
(define highest-score judges[j])]
[else
(judges[i] judges[j])
(judges[j] judges[j +1])])]
[else
(cond [(equal? judges[i] judges[length -1])
(define highest-score judges[i])]
[else
(judges[j] judges[j +1])])]))
I want to be able to find the largest number in a set of values, which for this problem includes values from judge1, judge2... judge8. The way I'm trying to solve this problem is by taking the first two numbers on a list and comparing them; I can't seem to find much on DrRacket documentation on proper syntax for the type of operation I want to perform.
An easy way (in terms of writing code) to find the the maximum element is to sort the list, and grab the last element of that list. As #pdoherty926 mentioned, the easiest way to sort a list in Racket is with the sort function. You just give it a list and a comparitor, and it sorts the list for you:
> (sort '(5 2 6 1) <)
'(1 2 5 6)
And since you want the max value just grab the last element:
> (last (sort '(5 2 6 1) <))
6
Although if you want to find the maximum value of other (non-list) data structures, for is an attractive option. While your algorithm looks good, your syntax is off. In this particular case, I would actually recommend using for/fold. Basically, it lets you have an accumulator, which will hold your highest judge so far, as well as the list of judges you are iterating through, and the body for how you want to modify the accumulator. In this case, your loop will look something like:
;; A judge is a non-negative number
(define judges '(5 6 1 2))
(for/fold ([largest -1])
([j (in-list judges)])
...)
Where you replace the ... with the next value for largest. The entire loop evaluates to the final value for largest.
The interesting thing here is that j is an actual judge, not just an index to the judges list. So your body does not need to refer to the judges list at all. It should look something like:
(max j largest)
Since a judge is just a number. I will leave you to put the body in the loop as an exercise.
As an aside, since judges are just numbers, you can just use max directly with apply:
> (apply max '(5 6 1 2))
6
As one additional note, if for some reason you do want the actual index of the current judge you are examining, you can use in-naturals:
(for/fold ([largest -1])
([j (in-list judges)]
[index (in-naturals)])
...)
Following recursive function also works to find largest number in a list:
(define (largestnum slist)
(cond
((= (length slist) 2) ; if only 2 numbers, compare them
(if (> (car slist) (list-ref slist 1))
(car slist)
(list-ref slist 1)))
(else ; else recurse to compare car with largest of cdr
(let ((cdrLargest (largestnum (cdr slist))))
(if (> (car slist) cdrLargest)
(car slist)
cdrLargest)))))
(define judges '(5 6 1 2))
(largestnum judges)
Output:
6
I was asked in an internship interview to do a R5RS program that creates a function, let's say two-subsets. This function has to return #t if the list L contains two subsets with equal sums of elements and with equal numbers of elements, otherwise it returns #f. It takes in entry the list L (only positive numbers) and some parameters (that I judge useful. There is no conditions on the number of parameters) all equal to 0 at the beginning.
The requirements as I still remember were as follow:
- Do not define other functions and call them inside the "two-subsets" function.
- It can only use the following constructs: null?, cond, car, cdr, else, + ,=, not, and, #t, #f, two-subsets (itself for recursive call), the names of the parameters, such as list, sum, ...etc, numeric constants and parentheses.
There were some given examples on the results that we are supposed to have, let's say:
(two-subsets '(7 7) 0 0 0) returns #t. The two subsets are {7} and {7}.
(two-subsets '(7 7 1) 0 0) returns #t. The two subsets are {7} and {7}.
(two-subsets '(5 3 2 4) 0 0) returns #t. The two subsets are {2, 5} and {3, 4}.
(two-subsets '(1 2 3 6 9) 0 0) returns #f.
I started by writing the signature that it looks to me it should be something like this:
(define two-subsets (lambda (L m n ... other parameters)
(cond
The problem is really complicated and it's complexity is obviously more than O(n), I read on it on https://en.wikipedia.org/wiki/Partition_problem .
I tried to start by defining the algorithm first before coding it. I thought about taking as parameters: sum of the list L so in my conditions I'll iterate only on the combinations which sum is <= sum(L)/2. By doing that I can reduce a little bit the complexity of the problem, but still I couldn't figure out how to do it.
It looks like an interesting problem and I really want to know more about it.
Here is a version which does not depend on the numbers being all positive. I am reasonably sure that, by knowing they are, you can do much better than this.
Note this assumes that:
the partition does not need to be exhaustive;
but the sets must not be empty.
I'd be very interested to see a version which relies on the elements of the list being +ve!
(define (two-subsets? l sl sld ssd)
;; l is the list we want to partition
;; sl is how many elements we have eaten from it so far
;; sld is the length difference in the partitions
;; ssd is the sum difference in the partitions
(cond [(and (not (= sl 0))
(= sld 0)
(= ssd 0))
;; we have eaten some elements, the differences are zero
;; we are done.
#t]
[(null? l)
;; out of l, failed
#f]
;; this is where I am sure we could be clever about the set containing
;; only positive numbers, but I am too lazy to think
[(two-subsets? (cdr l)
(+ sl 1)
(+ sld 1)
(+ ssd (car l)))
;; the left-hand set worked
#t]
[(two-subsets? (cdr l)
(+ sl 1)
(- sld 1)
(- ssd (car l)))
;; the right-hand set worked
#t]
[else
;; finally drop the first element of l and try the others
(two-subsets? (cdr l) sl sld ssd)]))
As part of some Eulerian travails, I'm trying to code a Sieve of Eratosthenes with a factorization wheel. My code so far is:
(defun ring (&rest content)
"Returns a circular list containing the elements in content.
The returned list starts with the first element of content."
(setf (cdr (last content)) content))
(defun factorization-wheel (lst)
"Returns a circular list containing a factorization
wheel using the list of prime numbers in lst"
(let ((circumference (apply #'* lst)))
(loop for i from 1 to circumference
unless (some #'(lambda (x) (zerop (mod i x))) lst)
collect i into wheel
finally (return (apply #'ring
(maplist
#'(lambda (x) ; Takes exception to long lists (?!)
(if (cdr x)
(- (cadr x) (car x))
(- circumference (car x) -1)))
wheel))))))
(defun eratosthenes (n &optional (wheel (ring 4 2)))
"Returns primes up to n calculated using
a Sieve of Eratosthenes and a factorization wheel"
(let* ((candidates (loop with s = 1
for i in wheel
collect (setf s (+ i s))
until (> s n))))
(maplist #'(lambda (x)
(if (> (expt (car x) 2) n)
(return-from eratosthenes candidates))
(delete-if
#'(lambda (y) (zerop (mod y (car x))))
(cdr x)))
candidates)))
I got the following result for wheels longer than 6 elements. I didn't really understand why:
21 > (factorization-wheel '(2 3 5 7 11 13))
(16 2 4 6 2 6 4 2 4 6 6 2 6 4 2 6 4 6 8 4 ...)
21 > (factorization-wheel '(2 3 5 7 11 13 17))
> Error: Too many arguments.
> While executing: FACTORIZATION-WHEEL, in process listener(1).
The algorithm seems to be working OK otherwise and churns out primes with wheels having 6 or fewer elements.
Apparently apply or ring turn up their noses when long lists are passed to them.
But shouldn't the list count as a single argument? I admit I'm thoroughly flummoxed. Any input is appreciated.
ANSI Common Lisp allows implementations to constrain the maximum number of arguments which can be passed to a function. This limit is given by call-arguments-limit can be as small as 50.
For functions which behave like algebraic group operators obeying the
associative property (+, list, and others), we can get around the limit by using reduce to decimate the input list while treating the function as binary.
For instance to add a large list of numbers: (reduce #'+ list) rather than (apply #'+ list).
Notes on reduce
In Common Lisp, reduce will appear to work even if the list is empty. Few other languages give you this, and it doesn't actually come from reduce: it won't work for all functions. But with + we can write (reduce #'+ nil) and it calculates zero, just like (apply #'+ nil).
Why is that? Because the + function can be called with zero arguments, and when called with zero arguments, it yields the identity element for the additive group: 0. This dovetails with the reduce function.
In some other languages the fold or reduce function must be given an initial seed value (like 0), or else a nonempty list. If it is given neither, it is an error.
The Common Lisp reduce, if it is given an empty list and no :initial-value, will call the kernel function with no arguments, and use the return value as the initial value. Since that value is then the only value (the list is empty), that value is returned.
Watch out for functions with special rules for the leftmost argument. For instance:
(apply #'- '(1)) -> -1 ;; same as (- 1), unary minus semantics.
(reduce #'- '(1)) -> 1 ;; what?
What's going on is that when reduce is given a one-element list, it just returns the element without calling the function.
Basically it is founded on the mathematical assumption mentioned above that if no :initial-value is supplied then f is expected to support (f) -> i, where i is some identity element in relation to f, so that (f i x) -> x. This is used as the initial value when reducing the singleton list, (reduce #'f (list x)) -> (f (f) x) -> (f i x) -> x.
The - function doesn't obey these rules. (- a 0) means "subtract zero from a" and so yields a, whereas (- a) is the additive inverse of a, probably for purely pragmatic, notational reasons (namely, not making Lisp programmers write (- 0 a) just to flip a sign, just for the sake of having - behave more consistently under reduce and apply). The - function also may not be called with zero arguments.
If we want to take a list of numbers and subtract them all from some value x, the pattern for that is:
(reduce #'- list-of-numbers :initial-value x)
I am Tasked (in exercise 8) with creating a function in Intermediate Student Language (Racket) that receives a list of numbers and a list of lists of numbers; each list is the same length. Name the first list breakpoints and the second LoR (list of rows). This function should be defined using map and should filter each row in LoR so that only numbers larger than that the n'th row in LoR only contains values larger than the n'th value in breakpoints-- here is an example for clarity:
(define breakpoints (list 7 2 15))
(define LoR (list (list 3 25 13)
(list 1 2 11)
(list 22 4 8)))
would output...
(list (list 25 13) (list 11) (list 22))
Doing this without using map would be fine and I understand the problem in that sense, but I am having trouble figuring out how to use map. I was thinking recursively in the sense that if the list of rows is not empty, I would cons the (filtered first row) to the (recursive call of the function using the rest of breakpoints and LoR) as so:
(define (parallel-filter breakpoints LoR)
(cond((empty? breakpoints) empty)
(else (cons ...
(parallel-filter (rest breakpoints) (rest LoR))))))
However, I'm not sure how to replace the ellipse with a map statement that would make the function work correctly-- as I understand, map's first parameter must be a one-parameter function and I'm not sure how to use map for this purpose. How do I proceed?
edited to correct output
We can solve this problem by combining map and filter, but first bear in mind this:
You can't use just map, because it will always return a list of the same length as the original. For excluding some elements we must use filter (or alternatively: use foldr to implement our own version of filter)
map can receive more than one list as parameter, as long as its function receives enough parameters - one from each list
Your sample output is wrong for the first sublist
With all of the above in mind, here's one possible solution:
(define (parallel-filter breakpoints LoR)
(map (lambda (brk lst) ; `brk` is from `breakpoints` and `lst` is from `LoR`
(filter (lambda (ele) (> ele brk)) ; filter each sublist from `LoR`
lst))
breakpoints
LoR))
It works as expected:
(parallel-filter breakpoints LoR)
=> (list (list 25 13) (list 11) (list 22))