I have the following function:
(defun chooseBest (TSPs dTSPs)
(let ((minim (minPos dTSPs 0 0)) (j 0) (best nil))
(loop for i in TSPs
do (cond ((= j minim) (progn (setf best i) (setq j (+ j 1))))
(t (setq j (+ j 1)))))
best))
This function receives two lists:
TSPs - a list of paths like this one:
(((1 3600 2300) (2 3100 3300))
((3 4700 5750) (22 6650 2300) (23 5400 1600)))
and a list of distances associated with these:
(distancePath1 distancePath2)
The function minPos returns the position of the list with a smaller number that is the path with smaller distance.
Given this, the chooseBest function will return the smaller path.
But I want to improve it, because it will search the whole list for the small number and it is a waste because the minim has that position. For example minim is 2, but it is evaluating a TSPs list with 100 paths, I want to return immediately on 2 and break the loop, but return doesn't work...
Let's rework your function a bit.
First, with better indentation:
(defun chooseBest (TSPs dTSPs)
(let ((minim (minPos dTSPs 0 0))
(j 0)
(best nil))
(loop for i in TSPs
do (cond ((= j minim)
(progn (setf best i)
(setq j (+ j 1))))
(t
(setq j (+ j 1)))))
best))
No need of the progn inside the cond:
do (cond ((= j minim)
(setf best i)
(setq j (+ j 1)))
(t
(setq j (+ j 1)))))
Incrementing j can be done with incf:
(setq j (+ j 1)))
=>
(incf j)
You can move the let variables into the loop.
(let ((minim (minPos dTSPs 0 0))
(j 0)
(best nil))
(loop for i in TSPs
=>
(loop for it in TSPs
for j from 0
with minim = (minPos dTSPs 0 0)
with best
do …)
for j from 0 starts a counter, with … = declares a variable which is calculated at the beginning (and not at every iteration).
Returns and conditionals
Inside a loop, we can use if…do, else…do, when and return, and more than once. To do something at the end of the loop, use finally.
(defun chooseBest (TSPs dTSPs)
(loop for i in TSPs
for j from 0
with minim = (minPos dTSPs 0 0)
with best
if (= j minim)
do (progn (setf best i)
(incf j))
else
do (incf j)
finally (return best)))
Functions to search lists and sequences
Now if you want to find an element inside a list, you have lots of functions for that: find, nth, search, position,… see https://lispcookbook.github.io/cl-cookbook/data-structures.html#functions Since minPos returns an index, you probably want nth index list or elt sequence index.
If you want the nth element of a list, you can use the function nth: (nth position list)
CL-USER 15 > (nth 0 '(((1 3600 2300) (2 3100 3300))
((3 4700 5750) (22 6650 2300) (23 5400 1600))))
((1 3600 2300) (2 3100 3300))
CL-USER 16 > (nth 1 '(((1 3600 2300) (2 3100 3300))
((3 4700 5750) (22 6650 2300) (23 5400 1600))))
((3 4700 5750) (22 6650 2300) (23 5400 1600))
If you want to return from a loop, you can use the operator return:
CL-USER > (loop for i from 10
when (= i (expt (isqrt i) 2))
do (return i))
16
Related
I'm trying to write a program that returns the Pell numbers sequence based on a given number.
For example (pellNumb 6) should return a list (0 1 2 5 12 29 70)
This is my code so far.
I am able of calculating the numbers, but I am not able of skipping the double recursion.
(defun base (n)
(if (= n 0)
0
(if (= n 1)
1)))
(defun pellNumb (n)
(if (or (= n 0) (= n 1))
(base n)
(let ((x (pellNumb (- n 2))))
(setq y (+ (* 2 (pellNumb (- n 1))) x))
(print y))))
The output for (pellNumb 4) is 2 2 5 12, and this is because i'm recursing to (pellNumb 2) twice.
Is there a way to skip that, and store these values in a list ?
Thanks!
Get the nth number
Yes, there is a way - use multiple values:
(defun pell-numbers (n)
"Return the n-th Pell number, n-1 number is returned as the 2nd value.
See https://oeis.org/A000129, https://en.wikipedia.org/wiki/Pell_number"
(check-type n (integer 0))
(cond ((= n 0) (values 0 0))
((= n 1) (values 1 0))
(t (multiple-value-bind (prev prev-1) (pell-numbers (1- n))
(values (+ (* 2 prev) prev-1)
prev)))))
(pell-numbers 10)
==> 2378 ; 985
This is a standard trick for recursive sequences which depend on several previous values, such as the Fibonacci.
Performance
Note that your double recursion means that (pell-numbers n) has exponential(!) performance (computation requires O(2^n) time), while my single recursion is linear (i.e., O(n)).
Moreover, Fibonacci numbers have a convenient property which allows a logarithmic recursive implementation, i.e., taking O(log(n)) time.
Get all the numbers up to n in a list
If you need all numbers up to the nth, you need a simple loop:
(defun pell-numbers-loop (n)
(loop repeat n
for cur = 1 then (+ (* 2 cur) prev)
and prev = 0 then cur
collect cur))
(pell-numbers-loop 10)
==> (1 2 5 12 29 70 169 408 985 2378)
If you insist on recursion:
(defun pell-numbers-recursive (n)
(labels ((pnr (n)
(cond ((= n 0) (list 0))
((= n 1) (list 1 0))
(t (let ((prev (pnr (1- n))))
(cons (+ (* 2 (first prev)) (second prev))
prev))))))
(nreverse (pnr n))))
(pell-numbers-recursive 10)
==> (0 1 2 5 12 29 70 169 408 985 2378)
Note that the recursion is non-tail, so the loop version is probably more efficient.
One can, of course, produce a tail recursive version:
(defun pell-numbers-tail (n)
(labels ((pnt (i prev)
(if (= i 0)
prev ; done
(pnt (1- i)
(cond ((null prev) (list 0)) ; n=0
((null (cdr prev)) (cons 1 prev)) ; n=1
(t
(cons (+ (* 2 (or (first prev) 1))
(or (second prev) 0))
prev)))))))
(nreverse (pnt (1+ n) ()))))
(pell-numbers-tail 10)
==> (0 1 2 5 12 29 70 169 408 985 2378)
This procedure takes a non-negative integer n and creates a list of all lists of n 0's or 1's in the specific order required for a truth table. I am just trying to understand how the map portion of the procedure works. I am particularly confused as to how append, map, and the recursive call to all-lists are working together in the second argument of the if. Any help would be greatly greatly appreciated!
(define all-lists
(lambda (n)
(if (= n 0)
'(())
(append (map (lambda (k) (cons 0 k)) (all-lists (- n 1)))
(map (lambda (k) (cons 1 k)) (all-lists (- n 1)))
))))
The best strategy to understand a recursive function is to try it with the case sligthly more complex than the terminal one. So, let's try it with n=1.
In this case, the function becomes:
(append (map (lambda (k) (cons 0 k)) (all-lists 0))
(map (lambda (k) (cons 1 k)) (all-lists 0))
that is:
(append (map (lambda (k) (cons 0 k)) '(()))
(map (lambda (k) (cons 1 k)) '(())))
So, the first map applies the function (lambda (k) (cons 0 k)) to all the elements of the list '(())), which has only an element, '(), producing '((0)) (the list containing an element obtained by the cons of 0 and the empty list), and in the same way the second map produces '((1)).
These lists are appended together yielding the list '((0) (1)), in other words, the list of all the lists of length 1 with all the possible combinations of 0 and 1.
In the case of n=2, the recursive case is applied to '((0) (1)): so the first map puts a 0 before all the elements, obtaining '((0 0) (0 1)), while the second map produces '((1 0) (1 1)). If you append together these two lists, you obtain '((0 0) (0 1) (1 0) (1 1)), which is the list of all the possible combinations, of length 2, of 0 and 1.
And so on, and so on...
Actually, the function is not well defined, since it calculates unnecessarily the value of (all-lists (- n 1)) two times at each recursion, so doubling its work, which is already exponential. So it could be made much more efficient by computing that value only once, for instance in the following way:
(define all-lists
(lambda (n)
(if (= n 0)
'(())
(let ((a (all-lists (- n 1))))
(append (map (lambda (k) (cons 0 k)) a)
(map (lambda (k) (cons 1 k)) a))))))
Separating statements along with 'println' can help understand what is happening:
(define (all-lists n)
(if (= n 0)
'(())
(let* ((a (all-lists (- n 1)))
(ol1 (map (λ (k) (cons 0 k)) a))
(ol2 (map (λ (k) (cons 1 k)) a))
(ol (append ol1 ol2)))
(println "---------")
(println ol1)
(println ol2)
(println ol)
ol)))
(all-lists 3)
Output:
"---------"
'((0))
'((1))
'((0) (1))
"---------"
'((0 0) (0 1))
'((1 0) (1 1))
'((0 0) (0 1) (1 0) (1 1))
"---------"
'((0 0 0) (0 0 1) (0 1 0) (0 1 1))
'((1 0 0) (1 0 1) (1 1 0) (1 1 1))
'((0 0 0) (0 0 1) (0 1 0) (0 1 1) (1 0 0) (1 0 1) (1 1 0) (1 1 1))
'((0 0 0) (0 0 1) (0 1 0) (0 1 1) (1 0 0) (1 0 1) (1 1 0) (1 1 1))
One can clearly see how outlists (ol1, ol2 and combined ol) are changing at each step.
sort code, which is basically a translation i made from this one:
insertion(A)
for i from 2 to n
j=i-1
while (j>=1) AND (A[j]>A[j+1])do
t=A[j+1]
A[j+1]=A[j]
A[j]=t
j=j-1
and my translation to lisp is
(defun insertion (unsorted-vector)
(let ((vector (copy-seq unsorted-vector))
(n (length unsorted-vector)))
(loop :for i : from 2: below (n)
:do ((j (- i 1))
(loop :do (AND (>= (j 1))
(> (aref vector j) (aref vector (+ j 1))))
(rotatef (aref vector j) (aref vector (+ j 1)))
(j (- j 1))))
vector)))
(insertion #(5 1 3 2))
but it is throwing me a message that says: Error while reading: #\Space is an illegal character after a colon. and i don´t understand what does it mean, and don´t know if there are any other mistakes in the code.
Because there is space. Look at your code, you should write :from or just from, not : from, and the same thing with below.
(defun insertion (unsorted-vector)
(let ((vector (copy-seq unsorted-vector))
(n (length unsorted-vector)))
(loop :for i : from 2: below (n) ;; your problem
;;; ^^^ ^^^ ;; <= is here
;;; Change to :from and :below
:do ((j (- i 1))
(loop :do (AND (>= (j 1))
(> (aref vector j) (aref vector (+ j 1))))
(rotatef (aref vector j) (aref vector (+ j 1)))
(j (- j 1))))
vector)))
I have some trouble fully understanding CL's Loop macro.
This is my code for Project Euler Nr. 32:
(defun number-to-list (nr)
(map 'list #'digit-char-p (prin1-to-string nr)))
(defun nine-digits-p (multiplicand multiplier )
(= (length (equationlist multiplicand multiplier
(* multiplicand multiplier))) 9))
(defun equationlist (multiplicand multiplier product)
(append (number-to-list multiplicand) (number-to-list multiplier)
(number-to-list product)))
(defun pandigital (multiplicand multiplier)
(equal (sort (equationlist multiplicand multiplier
(* multiplicand multiplier)) #'<)
'(1 2 3 4 5 6 7 8 9)))
(defun pandigital-list ()
(loop
for i from 1 to 2000 collect
(loop for j from 2 to 2000
when (and (nine-digits-p i j) (pandigital i j)) collect (* i j))))
(defun euler-32 ()
(reduce #'+ (reduce #'union (pandigital-list))))
Although this gives me the correct solution, my problem is with function "pandigital-list". Instead of collecting only the pandigital numbers, it returns a list filled with "NIL" and the few correct numbers.
How do I change this function to only return the numbers I am interested in ?
The problem is that the inner loop returns nil whenever it does not collect anything else. (Remember: in Common Lisp everything has a value.)
One solution is to redefine pandigital-list like this:
(defun pandigital-list ()
(loop for i from 1 to 2000
for sublist = (loop for j from 2 to 2000
when (and (nine-digits-p i j)
(pandigital i j))
collect (* i j))
when sublist collect sublist))
Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 10 years ago.
Improve this question
I just started learning common lisp and so I've been working on project euler problems. Here's my solution (with some help from https://github.com/qlkzy/project-euler-cl ). Do you guys have any suggestions for stylistic changes and the sort to make it more lisp-y?
; A palindromic number reads the same both ways. The largest palindrome made
; from the product of two 2-digit numbers is 9009 = 91 99.
; Find the largest palindrome made from the product of two 3-digit numbers.
(defun num-to-list (num)
(let ((result nil))
(do ((x num (truncate x 10)))
((= x 0 ) result)
(setq result (cons (mod x 10) result)))))
(defun palindrome? (num)
(let ((x (num-to-list num)))
(equal x (reverse x))))
(defun all-n-digit-nums (n)
(loop for i from (expt 10 (1- n)) to (1- (expt 10 n)) collect i))
(defun all-products-of-n-digit-nums (n)
(let ((nums (all-n-digit-nums n)))
(loop for x in nums
appending (loop for y in nums collecting (* x y)))))
(defun all-palindromes (n)
(let ((nums (all-products-of-n-digit-nums n)))
(loop for x in nums
when (palindrome? x) collecting x)))
(defun largest-palindrome (n)
(apply 'max (all-palindromes 3)))
(print (largest-palindrome 3))
Barnar's solution is great however there's just a small typo, to return a result it should be:
(defun largest-palindrome (n)
(loop with start = (expt 10 (1- n))
and end = (1- (expt 10 n))
for i from start to end
maximize (loop for j from i to end
for num = (* i j)
when (palindrome? num)
maximize num)))
(setq list (cons thing list))
can be simplified to:
(push thing list)
My other comments on your code are not so much about Lisp style as about the algorithm. Creating all those intermediate lists of numbers seems like a poor way to do it, just write nested loops that calculate and test the numbers.
(defun all-palindromes (n)
(loop for i from (expt 10 (1- n)) to (1- (expt 10 n))
do (loop for j from (expt 10 (1- n)) to (1- (expt 10 n))
for num = (* i j)
when (palindrome? num)
collect num)))
But LOOP has a feature you can use: MAXIMIZE. So instead of collecting all the palindroms in a list with COLLECT, you can:
(defun largest-palindrome (n)
(loop with start = (expt 10 (1- n))
and end = (1- (expt 10 n))
for i from start to end
do (loop for j from start to end
for num = (* i j)
when (palindrome? num)
maximize num)))
Here's another optimization:
(defun largest-palindrome (n)
(loop with start = (expt 10 (1- n))
and end = (1- (expt 10 n))
for i from start to end
do (loop for j from i to end
for num = (* i j)
when (palindrome? num)
maximize num)))
Making the inner loop start from i instead of start avoids the redundancy of checking both M*N and N*M.
The example below is a bit contrived, but it finds the palindrome in a lot less iterations than your original approach:
(defun number-to-list (n)
(loop with i = n
with result = nil
while (> i 0) do
(multiple-value-bind (a b)
(floor i 10)
(setf i a result (cons b result)))
finally (return result)))
(defun palindrome-p (n)
(loop with source = (coerce n 'vector)
for i from 0 below (floor (length source) 2) do
(when (/= (aref source i) (aref source (- (length source) i 1)))
(return))
finally (return t)))
(defun suficiently-large-palindrome-of-3 ()
;; This is a fast way to find some sufficiently large palindrome
;; that fits our requirement, but may not be the largest
(loop with left = 999
with right = 999
for maybe-palindrome = (number-to-list (* left right)) do
(cond
((palindrome-p maybe-palindrome)
(return (values left right)))
((> left 99)
(decf left))
((> right 99)
(setf left 999 right (1- right)))
(t ; unrealistic situation
; we didn't find any palindromes
; which are multiples of two 3-digit
; numbers
(return)))))
(defun largest-palindrome-of-3 ()
(multiple-value-bind (left right)
(suficiently-large-palindrome-of-3)
(loop with largest = (* left right)
for i from right downto left do
(loop for j from 100 to 999
for maybe-larger = (* i j) do
(when (and (> maybe-larger largest)
(palindrome-p (number-to-list maybe-larger)))
(setf largest maybe-larger)))
finally (return largest)))) ; 906609
It also tries to optimize a bit the way you check that number is a palindrome, for an additional memory cost though. It also splits the number into a list using somewhat longer code, but making less divisions (which are somewhat computationally expensive).
The whole idea is based on the concept that the largest palindrome will be somewhere more towards the... largest multipliers, so, by starting off with 99 * 99 you will have a lot of bad matches. Instead, it tries to go from 999 * 999 and first find some palindrome, which looks good, doing so in a "sloppy" way. And then it tries hard to improve upon the initial find.