清除列表中的任何重复列表。口齿不清

时间:2014-12-02 17:27:34

标签: common-lisp

这比标题所暗示的要复杂得多,但我无法将其浓缩为一句话。

我正在使用Clisp,目前有一个列表列表。外部列表是任意长的,而内部列表是4个整数长。这是我可能拥有的一个例子。

((2 1 1 0) (1 1 0 0) (1 0 0 1) (1 1 0 0) (1 0 1 0) (1 0 0 0))

现在每个内部列表由2个部分组成,第一个项目是“乘数”。最后3项只是列表中的值。所以在某种意义上,(10 1 1 0)与(5 1 1 0)(5 1 1 0)相同。

我需要一个可以压缩此列表的函数,因此没有2个列表包含相同的最后3个项目。但是每个唯一的最后3个项目只有一个列表,第一个空格中的值是这个列表的“多少”。如果这是有道理的......

所以这个

((2 1 1 0) (1 1 0 0) (1 0 0 1) (1 1 0 0) (1 0 1 0) (1 0 0 0))
;          ^                   ^

会成为这个

((2 1 1 0) (2 1 0 0) (1 0 0 1) (1 0 1 0) (1 0 0 0))
;          ^

我不知道采取这个方向的方向。并希望得到一些关于如何最好地解决这个问题的建议

2 个答案:

答案 0 :(得分:5)

在Common Lisp中,最简单的方法是使用哈希表构建数据的直方图,然后迭代哈希表以重新计算计数和密钥。以下直方图将直方图创建为哈希表:

(defun histogram (sequence &key hash-args key delta-key)
  "Create a histogram (hash-table) mapping elements to their frequencies.

* sequence---a proper sequence
* hash-args---a list of initargs for MAKE-HASH-TABLE, default is NIL
* key---a designator for a function of one argument, or NIL
* delta-key---a designator for a function of one argument, or NIL

HISTOGRAM returns a hash table mapping keys hash-keys extracted from
the elements of SEQUENCE by KEY to frequencies computed using
DELTA-KEY.  The hash table is created using HASH-ARGS as initargs.
The default is the empty list, in which case the hash-table will
compare hash keys with EQL.  HISTOGRAM iterates through the elements
of SEQUENCE, using KEY to extract a hash key from the element and
DELTA-KEY to extract an increment value, and increments the entry for
the hash key in the histogram by the increment value.

### See Also:
Section 17.2 (Rules about Test Functions), Section 3.6 (Traversal
Rules and Side Effects)"
  (flet ((key (x)
           (if (null key) x
               (funcall key x)))
         (delta (x)
           (if (null delta-key) 1
               (funcall delta-key x))))
    (let ((histogram (apply 'make-hash-table hash-args)))
      (prog1 histogram
        (map nil #'(lambda (element)
                     (incf (gethash (key element) histogram 0)
                           (delta element)))
             sequence)))))

然后编写一个函数来获取哈希表中的(value。key)对列表并不太难:

(defun hash-table-to-list (table)
  "Return a list of (VALUE . KEY) pairs based on TABLE."
  (loop 
     for k being each hash-key in table 
     using (hash-value v)
     collect (cons v k)))

要将此应用于您的数据,您需要一个相等哈希表,以便正确比较键(整数列表),并且键功能 rest ,因为你正在比较输入的尾部。 delta-key函数是 first ,因为你想通过列表中的第一个元素递增“count”。

CL-USER> (histogram '((2 1 1 0) (1 1 0 0) (1 0 0 1)
                      (1 1 0 0) (1 0 1 0) (1 0 0 0))
                    :hash-args '(:test equal)
                    :key 'rest
                    :delta-key 'first)
;=> #<HASH-TABLE :TEST EQUAL :COUNT 5 {10051558E3}>

CL-USER> (hash-table-to-list *)
;=> ((2 1 1 0) (2 1 0 0) (1 0 0 1) (1 0 1 0) (1 0 0 0))

CL-USER> (histogram '((5 1 1 0) (3 1 1 0) (1 0 0 1) (1 0 0 1))
                    :hash-args '(:test equal)
                    :key 'rest
                    :delta-key 'first)
;=> #<HASH-TABLE :TEST EQUAL :COUNT 2 {100527DA53}>

CL-USER> (hash-table-to-list *)
;=> ((8 1 1 0) (2 0 0 1))

答案 1 :(得分:2)

这是Racket的一个版本(抱歉,我不是Common Lisper,所以无法帮助):

(define (count-alist alist)
  (define ht (for/fold ((ht (hash)))
                       ((ass (in-list alist)))
               (hash-update ht (cdr ass) (curry + (car ass)) 0)))
  (for/list (((key val) (in-hash ht)))
    (cons val key)))

让我们用英语解决问题:

  1. 要收集&#34;三个数字&#34;的实际计数,请使用&#34;三个数字&#34;来构建哈希表。作为键,0作为默认值。
  2. 对于传入列表中的每个项目,您都要将计数添加到该值,然后使用该新值更新哈希表。
  3. 然后遍历您的哈希表以构建结果列表。