1

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...

1

2 Answers 2

3

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.

Sign up to request clarification or add additional context in comments.

Comments

0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.