Reputation: 29
I have this project in my AI course to make a few functions in lisp and I just can't get why one of my functions isn't working properly. The function is supposed to take a list as argument and return a list where the arguments from the given list which show up more then once are grouped together, something like this: (2, 4, 6, 5, 4, 6, 7, 2, 3, 4, 75, 87) -> ( 2, 2, 4, 4, 4, 6, 6, 5, 7,3, 75, 87). I first made two functions, one which deletes the given argument from the given list ( brisi ( x, l) ) and the other which counts how many times does element x shows up in list l ( brojPonavljanja (x, l) )
(defun brisi (x l)
(setq duz (length l))
(setq i 0)
(setq br 0)
(loop
(when (= i duz)
(return)
)
(when (= x (nth i l))
(incf br)
)
(incf i)
)
(setq duz1 (- duz br))
(setq l1 (make-list duz1))
(setq j 0)
(setq i 0)
(loop
(if (/= x (nth i l))
(progn
(setf (nth j l1) (nth i l))
(incf i)
(incf j)
)
(incf i)
)
(when (= i duz)
(return l1)
)
)
)
( defun brojPojava (x l)
(if ( null l)
0
( if (= (car l) x)
(+ 1 (brojPojava x (cdr l)))
(brojPojava x (cdr l))
)
)
)
(defun skupi(l)
(setq duz (length l))
(setq l1 (make-list duz))
(setq i 0)
(setq pos 0)
(loop
(when (= i (length l))
(return l1)
)
(setf elem (nth i l))
(setf br (brojPojava elem l))
(when (> br 1)
(setf l (brisi elem l))
(setq j 0)
(loop
(when (= br j)
(return)
)
(setf (nth pos l1) elem) ; <-- ######
(incf j)
(incf pos)
)
(setq i -1)
)
(incf i)
)
)
So the last function skupi(l) creates problems. I did notice a strange occurrence, at one point I use my brisi function to delete the element which repeats in the list and I copy it to a new list, but the list from which I deleted the repeating elements (list l) suddenly changes after one line of code (I put an arrow and couple of # on that line). I don't know why is this happening.
Upvotes: 0
Views: 477
Reputation: 21288
You could do it iteratively with two passes through the list and the help of some lookup tables (and some helper functions):
(defun gen-elements (element count)
(loop repeat count
collect element))
(defun group-list (list)
(let ((done (make-hash-table))
(counts (make-hash-table)))
(loop for element in list
do (incf (gethash element counts 0)))
(loop for element in list
if (not (gethash element done))
append (progn
(setf (gethash element done) t)
(gen-elements element (gethash element counts))))))
Upvotes: 0
Reputation: 1768
Your style doesn't resemble functional very much. You could write it, for example, in the following (not the most efficient, but more concise) way:
(defun group-list (lst)
(when lst
(nconc (make-list (count (car lst) lst) :initial-element (car lst))
(group-list (remove (car lst) lst)))))
though I'm providing the solution for the sake of learning, rather then for copy-pasting.
Upvotes: 2