【问题标题】:Splitting list based on missing numbers in a sequence根据序列中缺失的数字拆分列表
【发布时间】:2010-06-30 12:59:24
【问题描述】:

我正在寻找基于序列中缺少的数字将数字列表拆分为更小的列表的最 Pythonic 方法。例如,如果初始列表是:

seq1 = [1, 2, 3, 4, 6, 7, 8, 9, 10]

函数会产生:

[[1, 2, 3, 4], [6, 7, 8, 9, 10]]

seq2 = [1, 2, 4, 5, 6, 8, 9, 10]

会导致:

[[1, 2], [4, 5, 6], [8, 9, 10]]

【问题讨论】:

  • 你怎么知道哪个号码“丢失”了?您是否要求序列是没有重复的简单升序整数?请说明查找缺失值的规则。
  • 您是否有一些您认为不是 Python 风格的工作代码可以发布?
  • 你想要它做什么?我有一个代码 sn-p 用于减少可以将连续数字表示为范围的数字序列:例如[[1,4],[6,10]]

标签: python list sequence


【解决方案1】:

Python 3 版本的代码来自旧的Python documentation

>>> # Find runs of consecutive numbers using groupby.  The key to the solution
>>> # is differencing with a range so that consecutive numbers all appear in
>>> # same group.
>>> from itertools import groupby
>>> from operator import itemgetter
>>> data = [ 1,  4,5,6, 10, 15,16,17,18, 22, 25,26,27,28]
>>> for k, g in groupby(enumerate(data), lambda i_x: i_x[0] - i_x[1]):
...     print(list(map(itemgetter(1), g)))
...
[1]
[4, 5, 6]
[10]
[15, 16, 17, 18]
[22]
[25, 26, 27, 28]

来自 itertools 模块的 groupby 函数在每次 key 函数更改其返回值时生成一个中断。诀窍是返回值是列表中的数字减去列表中元素的位置。当数字有差距时,这种差异会发生变化。

itemgetter 函数来自 operator module,您必须导入它和 itertools 模块才能使本示例正常工作。

或者,作为列表理解:

>>> [map(itemgetter(1), g) for k, g in groupby(enumerate(seq2), lambda i_x: i_x[0] - i_x[1])]
[[1, 2], [4, 5, 6], [8, 9, 10]]

【讨论】:

  • 还应该发布初始序列不是整数时的解决方案!漂浮?日期时间?
【解决方案2】:

这是一个适用于 Python 3 的解决方案(基于之前仅适用于 python 2 的答案)。

>>> from operator import itemgetter
>>> from itertools import *
>>> groups = []
>>> for k, g in groupby(enumerate(seq2), lambda x: x[0]-x[1]):
>>>     groups.append(list(map(itemgetter(1), g)))
... 
>>> print(groups)
[[1, 2], [4, 5, 6], [8, 9, 10]]

或作为列表理解

>>> [list(map(itemgetter(1), g)) for k, g in groupby(enumerate(seq2), lambda x: x[0]-x[1])]
[[1, 2], [4, 5, 6], [8, 9, 10]]

需要进行更改,因为

  • 删除元组参数解包PEP 3113
  • map 返回迭代器而不是列表

【讨论】:

    【解决方案3】:

    另一个不需要 itertools 等的选项:

    >>> data = [1, 4, 5, 6, 10, 15, 16, 17, 18, 22, 25, 26, 27, 28]
    >>> spl = [0]+[i for i in range(1,len(data)) if data[i]-data[i-1]>1]+[None]
    >>> [data[b:e] for (b, e) in [(spl[i-1],spl[i]) for i in range(1,len(spl))]]
    ... [[1], [4, 5, 6], [10], [15, 16, 17, 18], [22], [25, 26, 27, 28]]
    

    【讨论】:

      【解决方案4】:

      我更喜欢这个,因为它不需要任何额外的库或对第一种情况进行特殊处理:

      a = [1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 15, 16, 17, 18, 20, 21, 22]
      b = []
      subList = []
      prev_n = -1
      
      for n in a:
          if prev_n+1 != n:            # end of previous subList and beginning of next
              if subList:              # if subList already has elements
                  b.append(subList)
                  subList = []
          subList.append(n)
          prev_n = n
      
      if subList:
          b.append(subList)
      
      print a
      print b
      

      输出:

      [1、2、3、4、5、6、7、8、10、11、12、15、16、17、18、20、21、22]

      [[1, 2, 3, 4, 5, 6, 7, 8], [10, 11, 12], [15, 16, 17, 18], [20, 21, 22]]

      【讨论】:

        【解决方案5】:

        我的方式

        alist = [1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 15, 16, 17, 18, 20, 21, 22]
        newlist = []
        start = 0
        end = 0
        for index,value in enumerate(alist):
            if index < len(alist)-1:
                if alist[index+1]> value+1:
                    end = index +1
                    newlist.append(alist[start:end])
                    start = end
            else:
                    newlist.append(alist[start: len(alist)])
        print(newlist)
        

        结果

        [[1, 2, 3, 4, 5, 6, 7, 8], [10, 11, 12], [15, 16, 17, 18], [20, 21, 22]]
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-10-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-04-22
          相关资源
          最近更新 更多