【问题标题】:Common lisp workin with listCommon lisp 与列表一起工作
【发布时间】:2016-12-18 17:37:55
【问题描述】:

我的任务是计算列表中所有重复的元素,例如 ( 2 2 (3 3) 4 (3)) 将导致 2 (因为只有 2 和 3 有重复) Searchdeep - 如果WHAT 不在列表WHERE 中,则返回零 Count2 - 遍历单个元素和子列表

如果找到原子,他将使用SEARCHDEEP 来确定它是否有重复,然后将检查列表OUT(以确保该原子是否尚未计算在内(例如,如 (3 3 3),其中应该返回 1,而不是 2) ,增加计数器并将原子添加到OUT 列表中。

但是,我不明白为什么,但它总是只返回1。我认为这是某种逻辑错误或函数使用错误。

我的代码是:

(SETQ OUT NIL)
(SETQ X (LIST  2 -3 (LIST 4 3 0 2) (LIST 4 -4) (LIST 2 (LIST 2 0 2))-5)) 
(SETQ count 0)
(DEFUN SEARCHDEEP (WHAT WHERE)    (COND
    ((NULL WHERE) NIL)
    (T (OR 
            (COND 
                ((ATOM (CAR WHERE)) (EQUAL WHAT (CAR WHERE)))
                (T (SEARCHDEEP WHAT  (CAR WHERE)))
            )
            (SEARCHDEEP WHAT (CDR WHERE))
        )
    )
)
)
(DEFUN Count2 ( input) 
(print input)
(COND
    ((NULL input) NIL)
    (T  
        (or
            (COND 
                ((ATOM (CAR input)) 
                            (COND 
                                (
                                    (and ;if
                                        (SEARCHDEEP (CAR INPUT) (CDR INPUT))
                                        (NOT (SEARCHDEEP (CAR INPUT) OUT))
                                    ) 
                                    (and ;do
                                        (Setq Count (+ count 1)) 
                                        (SETQ OUT (append OUT (LIST (CAR INPUT))))
                                        (Count2 (CDR input))
                                    )
                                )
                                (t (Count2 (CDR input)))
                            )
                )
                (T (Count2 (CAR input)))
            )
            (Count2 (CDR input))
        )
    )
)
)
(Count2 x)
(print count)

【问题讨论】:

标签: functional-programming common-lisp


【解决方案1】:

首先,您的代码存在一些大的样式问题。不要大写(有些人,像我一样,喜欢在 cmets 和代码之外的文本中用大写符号写符号,但代码本身应该小写),并且不要将括号放在自己的行中。所以SEARCHDEEP 函数应该看起来更像

(defun search-deep (what where)
  (cond ((null where) nil)
        (t (or (cond ((atom (car where)) (equal what (car where)))
                     (t (searchdeep what (car where))))
               (searchdeep what (cdr where))))))

您也不应该使用SETQ 来定义变量。请改用DEFPARAMETERDEFVAR,尽管在这种情况下,您首先不应使用全局变量。您应该在名称周围使用星号命名全局变量(*X* 而不是 x,但使用更具描述性的名称)。

对于问题本身,我会先写一个函数来遍历一棵树。

(defun traverse-tree (function tree)
  "Traverse TREE, calling FUNCTION on every atom."
  (typecase tree
    (atom (funcall function tree))
    (list (dolist (item tree)
            (traverse-tree function item))))
  (values))

请注意,在这种情况下,TYPECASECOND 更具可读性。您还应该使用该语言提供的映射或循环结构,而不是自己编写递归循环。最后的(values) 表示该函数不会返回任何内容。

(let ((tree '(2 -3 (4 3 0 2) (4 -4) (2 (2 0 2)) -5)))
  (traverse-tree (lambda (item)
                   (format t "~a " item))
                 tree))
; 2 -3 4 3 0 2 4 -4 2 2 0 2 -5 
; No values

如果您经常遍历树,则可以将该函数隐藏在 DO-TREE 宏后面

(defmacro do-tree ((var tree &optional result) &body body)
  `(progn (traverse-tree (lambda (,var)
                           ,@body)
                         ,tree)
          ,result))

(let ((tree '(2 -3 (4 3 0 2) (4 -4) (2 (2 0 2)) -5)))
  (do-tree (item tree)
    (format t "~a " item)))
; 2 -3 4 3 0 2 4 -4 2 2 0 2 -5 
;=> NIL

使用它,我们可以编写一个函数来计算树中的每个元素,并返回一个 alist。我将使用哈希表来跟踪计数。如果您只对保持在小范围内的数字感兴趣,则可能需要使用向量。

(defun tree-count-elements (tree &key (test 'eql))
  "Count each item in TREE. Returns an alist in 
form ((item1 . count1) ... (itemn . countn))"
  (let ((table (make-hash-table :test test)))
    (do-tree (item tree)
      (incf (gethash item table 0)))
    (loop for value being the hash-value in table using (hash-key key)
          collect (cons key value))))

(let ((tree '(2 -3 (4 3 0 2) (4 -4) (2 (2 0 2)) -5)))
  (tree-count-elements tree))
;=> ((2 . 5) (-3 . 1) (4 . 2) (3 . 1) (0 . 2) (-4 . 1) (-5 . 1))

该函数采用TEST 的关键字参数来与哈希表一起使用。对于数字或字符,EQL 有效。

现在您可以使用标准的COUNT-IF-函数来计算多次出现的元素。

(let ((tree '(2 -3 (4 3 0 2) (4 -4) (2 (2 0 2)) -5)))
  (count-if (lambda (item)
              (> item 1))
            (tree-count-elements tree)
            :key #'cdr))
;=> 3

【讨论】:

  • 问题是,我必须使用教授提供的函数,我的代码中几乎都提到了它们,所以我不能使用你的代码。
  • @rainbowShiningUnicorn 您应该将其添加到您的问题中(带有允许的功能列表)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-04
  • 1970-01-01
  • 1970-01-01
  • 2012-08-06
  • 1970-01-01
  • 2011-09-05
相关资源
最近更新 更多