【问题标题】:rearrange list elements in lisp在 lisp 中重新排列列表元素
【发布时间】:2016-01-20 22:36:53
【问题描述】:

我在我的 AI 课程中有一个项目,用于在 lisp 中创建一些函数,但我不明白为什么我的一个函数不能正常工作。该函数应该将一个列表作为参数并返回一个列表,其中给定列表中出现多次的参数组合在一起,如下所示: (2, 4, 6, 5, 4, 6, 7, 2, 3, 4, 75, 87) -> (2, 2, 4, 4, 4, 6, 6, 5, 7,3, 75, 87)。 我首先创建了两个函数,一个从给定列表中删除给定参数( brisi ( x, l) ),另一个计算元素 x 在列表 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)
  )
)

所以最后一个函数 skupi(l) 会产生问题。我确实注意到了一件奇怪的事情,有一次我使用我的 brisi 函数删除了在列表中重复的元素并将其复制到一个新列表中,但是我从中删除重复元素的列表(列表 l)突然改变了一行代码(我在那一行放了一个箭头和几个#)。我不知道为什么会这样。

【问题讨论】:

  • 你为什么在everywhere使用全局变量?
  • 你应该使用LET在函数中绑定局部变量。
  • 只需对列表进行排序,您就可以将所有相似的元素组合在一起。
  • 项目的一部分是我们自己制作所有这些
  • setq alters 一个已经存在的变量。该变量可以定义为参数、let 变量或使用defparameterdefvardeclare 全局定义。由于我们看到 duz 没有定义,我们可以假设它们是名称不好的全局变量(没有 *earmuffs*

标签: list lisp common-lisp


【解决方案1】:

你的风格不太像实用。例如,您可以按以下方式(不是最有效,但更简洁)编写它:

(defun group-list (lst)
  (when lst
    (nconc (make-list (count (car lst) lst) :initial-element (car lst))
      (group-list (remove (car lst) lst)))))

虽然我提供解决方案是为了学习,而不是为了复制粘贴。

【讨论】:

  • 谢谢,这正是我所描述的。我对递归不是很满意,所以我避免了它,但这确实比我的想法更简洁
  • @waltdisney 如果您要使用此解决方案,我建议您尝试优化它(为了学习),因为目前它每一步遍历列表两次,但可以做到只有一次。
  • 哦,我明白了,好吧,那我会尽量让它尽可能优化
【解决方案2】:

您可以通过两次遍历列表和一些查找表(和一些辅助函数)的帮助来迭代地完成它:

(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))))))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-05-08
    • 1970-01-01
    • 2012-02-07
    • 2019-04-23
    • 2011-12-09
    • 2019-06-24
    • 1970-01-01
    • 2017-06-13
    相关资源
    最近更新 更多