如何对给定系列的任何连续数字或项目进行分组

发布于 2024-12-06 11:05:17 字数 1056 浏览 0 评论 0原文

我正在尝试对给定系列的任何连续数字或项目进行分组。

所有连续数字 1 作为子列表返回。

(defun length1-to-atom (l)
  (loop for x in l collect (if (= (length x) 1) (car x) x)))

(defun group-series (n list)
  (length1-to-atom
   (reduce (lambda (item result)
             (cond
              ((endp result) (list (list item)))
              ((and (eql (first (first result)) item) (= n item))
               (cons (cons item (first result))
                     (rest result)))
              (t (cons (list item) result))))
           list
           :from-end t
           :initial-value '())))

(group-series 1 '(1 1 2 3 1 1 1 2 2 1 5 6 1 1))
;=> ((1 1) 2 3 (1 1 1) 2 1 5 6 (1 1))

(group-series 2 '(1 1 2 3 1 1 1 2 2 1 5 6 1 1))
;=> (1 1 2 3 1 1 1 (2 2) 1 5 6 1 1)

找不到以下示例的任何解决方案

(group-series '(1 2) '(1 1 2 3 1 1 1 2 1 5 6 1 1))
;=> ((1 (1 2) 3 1 1 (1 2) 1 5 6 1 1))

(group-series '(1 2 1) '(1 1 2 3 1 1 1 2 1 5 6 1 1))
;=> ((1 1 2 3 1 1 (1 2 1) 5 6 1 1))

非常感谢任何帮助。

I am trying to group any consecutive numbers or items of a given series.

all consecutive number 1 is return as a sublist.

(defun length1-to-atom (l)
  (loop for x in l collect (if (= (length x) 1) (car x) x)))

(defun group-series (n list)
  (length1-to-atom
   (reduce (lambda (item result)
             (cond
              ((endp result) (list (list item)))
              ((and (eql (first (first result)) item) (= n item))
               (cons (cons item (first result))
                     (rest result)))
              (t (cons (list item) result))))
           list
           :from-end t
           :initial-value '())))

(group-series 1 '(1 1 2 3 1 1 1 2 2 1 5 6 1 1))
;=> ((1 1) 2 3 (1 1 1) 2 1 5 6 (1 1))

(group-series 2 '(1 1 2 3 1 1 1 2 2 1 5 6 1 1))
;=> (1 1 2 3 1 1 1 (2 2) 1 5 6 1 1)

can't find any solution for the examples below

(group-series '(1 2) '(1 1 2 3 1 1 1 2 1 5 6 1 1))
;=> ((1 (1 2) 3 1 1 (1 2) 1 5 6 1 1))

or

(group-series '(1 2 1) '(1 1 2 3 1 1 1 2 1 5 6 1 1))
;=> ((1 1 2 3 1 1 (1 2 1) 5 6 1 1))

Any help much appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

风蛊 2024-12-13 11:05:17

第一种情况(查找单个项目的重复项)可以使用以下函数来解决:

(defun group-series-1 (x list)
  (let (prev
        rez)
    (dolist (elt list)
      (setf rez (if (and (equal elt x)
                         (equal elt prev))
                    ;; found consecutive number
                    (cons (cons elt (mklist (car rez)))
                          (cdr rez)))
                    (cons elt
                          (if (and rez (listp (car rez)))
                              ;; finished a series
                              (cons (reverse (car rez))
                                    (cdr rez))
                              ;; there was no series
                              rez)))
            prev elt))
    (reverse rez)))

其中:

(defun mklist (x)
  (if (consp x) x (list x)))

第二种情况可以使用类似的方法来解决,但代码量会增加两倍。

The first case (finding repetitions of a single item) can be solved with the following function:

(defun group-series-1 (x list)
  (let (prev
        rez)
    (dolist (elt list)
      (setf rez (if (and (equal elt x)
                         (equal elt prev))
                    ;; found consecutive number
                    (cons (cons elt (mklist (car rez)))
                          (cdr rez)))
                    (cons elt
                          (if (and rez (listp (car rez)))
                              ;; finished a series
                              (cons (reverse (car rez))
                                    (cdr rez))
                              ;; there was no series
                              rez)))
            prev elt))
    (reverse rez)))

where:

(defun mklist (x)
  (if (consp x) x (list x)))

The second one can be solved with the similar approach, but there will be twice as much code.

葬心 2024-12-13 11:05:17

我同意这个评论,组系列似乎在做两件不同的事情,具体取决于输入是列表还是项目。

如果输入是一个列表(第二种情况),这似乎符合规范:

(defun group-series (sublst lst)
  (funcall (alambda (lst res)
                    (if (null lst)
                      res
                      (if (equal (subseq lst 0 (min (length lst) (length sublst)))
                                 sublst)
                        (self (nthcdr (length sublst) lst) 
                              (nconc res (list sublst)))
                        (self (cdr lst)
                              (nconc res (list (car lst)))))))
           lst '()))

这利用了 Paul Graham 的 alambda 宏(http://lib.store.yahoo.net/lib/paulgraham/onlisp.pdf)。另请注意,由于匿名函数是一个闭包(即,它已关闭 sublst),因此它可以引用 sublst,而无需将其作为附加输入变量传递。

I agree with the comment, that group-series seems to be doing two separate things depending on if the input is a list or an item.

If the input is a list (the second case), this seems to meet the spec:

(defun group-series (sublst lst)
  (funcall (alambda (lst res)
                    (if (null lst)
                      res
                      (if (equal (subseq lst 0 (min (length lst) (length sublst)))
                                 sublst)
                        (self (nthcdr (length sublst) lst) 
                              (nconc res (list sublst)))
                        (self (cdr lst)
                              (nconc res (list (car lst)))))))
           lst '()))

This makes use of Paul Graham's alambda macro (http://lib.store.yahoo.net/lib/paulgraham/onlisp.pdf). Also note that because the anonymous function is a closure (i.e., it has closed over sublst), it can reference sublst without having to pass it around as an additional input variable.

岁月流歌 2024-12-13 11:05:17

许多评论说,这看起来像是该函数正在做两件不同的事情,但实际上有一种方法可以统一它正在做的事情。诀窍是将第一个参数视为列表指示符:

列表指示符 n。对象列表的指示符;那是,
表示列表的对象,并且是以下之一: 非零原子
(表示一个单例列表,其元素是非零原子)或
正确的列表(表示其本身)。

有了这种理解,我们可以将group-series视为采用列表子列表的指示符,并返回一个类似于列表的列表,只不过该子列表的所有连续出现都已被收集到一个新的子列表中。例如,

(group-series 1 '(1 2 1 1 2) ==
(group-series '(1) '(1 2 1 1 2)
;=> ((1) 2 (1 1) 2)

(group-series '(1 2) '(1 2 3 4 1 2 1 2 3 4))
;=> ((1 2) 3 4 (1 2 1 2) 3 4)

有了这样的理解,两种情况就变成了一种,我们只需要在开始时将第一个参数转换为指定的列表一次。然后很容易实现group-series,如下所示:

(defun group-series (sublist list)
  (do* ((sublist (if (listp sublist) sublist (list sublist)))
        (len (length sublist))
        (position (search sublist list))
        (result '()))
       ((null position)
        (nreconc result list))
    ;; consume any initial non-sublist prefix from list, and update
    ;; position to 0, since list then begins with the sublist.
    (dotimes (i position)
      (push (pop list) result))
    (setf position 0)
    ;; consume sublists from list into group until the list does not
    ;; begin with sublist.  add the group to the result.  Position is
    ;; left pointing at the next occurrence of sublist.
    (do ((group '()))
        ((not (eql 0 position))
         (push (nreverse group) result))
      (dotimes (i len)
        (push (pop list) group))
      (setf position (search sublist list)))))
CL-USER> (group-series 1 '(1 1 2 3 1 1 1 2 2 1 5 6 1 1))
((1 1) 2 3 (1 1 1) 2 2 (1) 5 6 (1 1))
CL-USER> (group-series 2 '(1 1 2 3 1 1 1 2 2 1 5 6 1 1))
(1 1 (2) 3 1 1 1 (2 2) 1 5 6 1 1)
CL-USER> (group-series '(1 2) '(1 1 2 3 1 1 1 2 1 5 6 1 1))
(1 (1 2) 3 1 1 (1 2) 1 5 6 1 1)
CL-USER> (group-series '(1 2 1) '(1 1 2 3 1 1 1 2 1 5 6 1 1))
(1 1 2 3 1 1 (1 2 1) 5 6 1 1)
CL-USER> (group-series '(a b) '(c a b a b c d e f a b))
(C (A B A B) C D E F (A B))

A number of comments say that this looks like the function is doing two different things, but there's actually a way to unify what it's doing. The trick is to treat the first argument a list designator:

list designator n. a designator for a list of objects; that is,
an object that denotes a list and that is one of: a non-nil atom
(denoting a singleton list whose element is that non-nil atom) or a
proper list (denoting itself).

With this understanding, we can see group-series as taking a designator for a sublist of list, and returning a list that's like list, except that all consecutive occurrences of the sublist have been collected into a new sublist. E.g.,

(group-series 1 '(1 2 1 1 2) ==
(group-series '(1) '(1 2 1 1 2)
;=> ((1) 2 (1 1) 2)

(group-series '(1 2) '(1 2 3 4 1 2 1 2 3 4))
;=> ((1 2) 3 4 (1 2 1 2) 3 4)

With that understanding, the two cases become one, and we just need to convert the first argument to the designated list once, at the beginning. Then it's easy to implement group-series like this:

(defun group-series (sublist list)
  (do* ((sublist (if (listp sublist) sublist (list sublist)))
        (len (length sublist))
        (position (search sublist list))
        (result '()))
       ((null position)
        (nreconc result list))
    ;; consume any initial non-sublist prefix from list, and update
    ;; position to 0, since list then begins with the sublist.
    (dotimes (i position)
      (push (pop list) result))
    (setf position 0)
    ;; consume sublists from list into group until the list does not
    ;; begin with sublist.  add the group to the result.  Position is
    ;; left pointing at the next occurrence of sublist.
    (do ((group '()))
        ((not (eql 0 position))
         (push (nreverse group) result))
      (dotimes (i len)
        (push (pop list) group))
      (setf position (search sublist list)))))
CL-USER> (group-series 1 '(1 1 2 3 1 1 1 2 2 1 5 6 1 1))
((1 1) 2 3 (1 1 1) 2 2 (1) 5 6 (1 1))
CL-USER> (group-series 2 '(1 1 2 3 1 1 1 2 2 1 5 6 1 1))
(1 1 (2) 3 1 1 1 (2 2) 1 5 6 1 1)
CL-USER> (group-series '(1 2) '(1 1 2 3 1 1 1 2 1 5 6 1 1))
(1 (1 2) 3 1 1 (1 2) 1 5 6 1 1)
CL-USER> (group-series '(1 2 1) '(1 1 2 3 1 1 1 2 1 5 6 1 1))
(1 1 2 3 1 1 (1 2 1) 5 6 1 1)
CL-USER> (group-series '(a b) '(c a b a b c d e f a b))
(C (A B A B) C D E F (A B))
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文