【问题标题】:LISP - count occurences of every value in a listLISP - 计算列表中每个值的出现次数
【发布时间】:2012-08-30 10:53:31
【问题描述】:

我为糟糕的英语道歉..
我的任务是编写一个名为“make-bag”的函数,该函数计算列表中每个值的出现次数
并返回一个点对列表,如下所示:'((value1 . num-occurences1) (value2 . num-occurences2) ...) 例如:

 (make-bag '(d c a b b c a))
((d . 1) (c . 2) (a . 2) (b . 2))

(列表不必排序)

我们的讲师允许我们使用函数MAPCARFILTER(假设它已实现), 但我们不允许使用REMOVE-DUPLICATESCOUNT-IF。 他还要求我们使用递归。

有没有办法只计算每个值一次而不删除重复项? 而如果有办法,可以通过递归来完成吗?

【问题讨论】:

  • Stackoverflow 不是家庭作业帮助的平台,尤其是如果你没有表现出任何努力来解决你遇到的问题。

标签: lisp common-lisp unique duplicate-removal


【解决方案1】:

首先,我同意 Joswig 先生的观点 - Stackoverflow 不是要求家庭作业答案的地方。但是,我将以一种你可能无法直接使用它的方式回答你的问题,而无需进行一些额外的挖掘,并且能够理解哈希表和词法闭包的工作原理。反过来,这将是你进步的一个很好的锻炼。

有没有办法只计算每个值一次而不删除重复项?而如果有办法,可以通过递归来完成吗?

是的,哈希表很简单,这里有两个例子:

;; no state stored
(defun make-bag (lst)
  (let ((hs (make-hash-table)))
    (labels ((%make-bag (lst)
               (if lst
                   (multiple-value-bind (val exists)
                       (gethash (car lst) hs)
                     (if exists
                         (setf (gethash (car lst) hs) (1+ val))
                         (setf (gethash (car lst) hs) 1))
                     (%make-bag (cdr lst)))
                   hs)))
      (%make-bag lst))))

现在,如果您尝试评估此表单两次,每次都会得到相同的答案:

(gethash 'a (make-bag '(a a a a b b b c c b a 1 2 2 1 3 3 4 5 55)))
> 5
> T

(gethash 'a (make-bag '(a a a a b b b c c b a 1 2 2 1 3 3 4 5 55)))
> 5
> T

这是第二个例子:

;; state is stored....
(let ((hs (make-hash-table)))
  (defun make-bag (lst)
    (if lst
        (multiple-value-bind (val exists)
            (gethash (car lst) hs)
          (if exists
              (setf (gethash (car lst) hs) (1+ val))
              (setf (gethash (car lst) hs) 1))
          (make-bag (cdr lst)))
        hs)))

现在,如果你尝试对这个表格进行两次评估,第二次你会得到双倍的答案:

(gethash 'x (make-bag '(x x x y y x z z z z x)))
> 5
> T

(gethash 'x (make-bag '(x x x y y x z z z z x)))
> 10
> T

为什么答案翻了一番?

如何将哈希表的内容转换为关联列表?

还要注意,递归函数通常会“吃”列表,有时还会有一个累加器,用于累加每一步的结果,并在最后返回。如果没有哈希表和使用 remove-duplicates/count-if 的能力,逻辑会变得有点复杂,因为您不得不使用基本功能。

【讨论】:

    【解决方案2】:

    嗯,这就是答案,但为了让它作为一个学习练习更有用,我会留下一些空白,你必须填写。

    另外请注意,使用哈希表来完成这项任务会更有利,因为对存储在哈希表中的元素的访问时间是固定的(通常非常小),而对存储在列表中的元素的访问时间有线性复杂度,因此会随着更长的列表而增长。

    (defun make-bag (list)
      (let (result)
        (labels ((%make-bag (list)
                   (when list
                     (let ((key (assoc (car <??>) <??>)))
                       (if key (incf (cdr key))
                           (setq <??>
                                 (cons (cons (car <??>) 1) <??>)))
                       (%make-bag (cdr <??>))))))
          (%make-bag list))
        result))
    

    这个函数可能有变体,但它们大致基于相同的原理。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-07-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多