如何将给定系列的任何连续数字或项目分组 [英] How to group any consecutive numbers or items of a given series

查看:63
本文介绍了如何将给定系列的任何连续数字或项目分组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

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

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

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

任何帮助

推荐答案

很多评论说,这看起来像函数在做两件事,但是实际上有一种方法统一它在做什么。诀窍是将第一个参数视为列表指示符

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

有了这样的理解,我们可以看到 group-series 用作指定列表的子列表的指示符,并返回类似于list的列表,只是该子列表的所有连续出现都已收集到一个新的子列表中。例如,

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)

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

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

这篇关于如何将给定系列的任何连续数字或项目分组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆