walt disney
walt disney

Reputation: 29

rearrange list elements in lisp

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

Answers (2)

Vatine
Vatine

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

tonso
tonso

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

Related Questions