如何将列表中的连续元素拆分为子列表

Posted

技术标签:

【中文标题】如何将列表中的连续元素拆分为子列表【英文标题】:How to split consecutive elements in a list into sublists 【发布时间】:2019-09-18 17:29:16 【问题描述】:

我有以下列表:

indices_to_remove: [0,1,2,3,..,600,800,801,802,....,1200,1600,1601,1602,...,1800]

我基本上有 3 个连续索引的子集:

    0-600 800-1200 1600-1800

我想创建 3 个仅包含连续数字的不同小列表。

预期结果:

indices_to_remove_1 : [0,1,2,3,....,600]
indices_to_remove_2 : [800,801,802,....,1200]
indices_to_remove_3 : [1600,1601,1602,....., 1800]

P.S:数字是任意随机的;此外,我可能会遇到超过 3 个或更少的子集。

【问题讨论】:

您想在空白处拆分列表吗? 基本上是的。最重要的是将连续索引拆分为一个子列表@StephenRauch 【参考方案1】:

我喜欢使用generators 来解决这类问题。你可以这样做:

拆分非连续数据:

def split_non_consequtive(data):
    data = iter(data)
    val = next(data)
    chunk = []
    try:
        while True:
            chunk.append(val)
            val = next(data)
            if val != chunk[-1] + 1:
                yield chunk
                chunk = []
    except StopIteration:
        if chunk:
            yield chunk

测试代码:

indices_to_remove = (
        list(range(0, 11)) +
        list(range(80, 91)) +
        list(range(160, 171))
)

for i in split_non_consequtive(indices_to_remove):
    print(i)

结果:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90]
[160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170]

【讨论】:

请注意,您可以在这里使用itertools.groupby...这有点难以理解,但相当巧妙:[[el[1] for el in g] for k, g in itertools.groupby(enumerate(indices_to_remove), lambda L: L[1] - L[0])]:p @JonClements,非常好! 谢谢@StephenRauch。但是,是否有任何可能的方法来修改代码以从生成的每个子列表中删除前三个元素? print(i[3:-3])yield chunk[3:-3] @Stephen 我隐约记得它是 Python 2.5 文档中 itertools 配方的一个例子,但从那以后就再也没有见过它了……只是想你可能会喜欢它:)跨度> 【参考方案2】:

另一种方法是使用more_itertools.consecutive_groups: (以@Stephen 的列表为例):

import more_itertools as mit
for group in mit.consecutive_groups(indices_to_remove):
    print(list(group))

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90]
[160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170]

【讨论】:

谢谢@anky_91 的回答,但我想知道是否可以消除我们创建的每个子列表的前两个元素。 再次感谢。 @anky_91 最后一个问题:我想知道是否有办法将在一个大列表中创建的所有子列表组合起来,我的主要目的是将列表拆分为子列表并删除第一个和最后 5 个元素,然后将它们组合在一个列表中。再次感谢 @AlexDavies 你的意思是[list(group)[2:-2] for group in mit.consecutive_groups(indices_to_remove)] ?? @andy_91,是的,我就是这个意思。使用它的唯一问题是它会在一个大列表中创建多个子列表。例如:list =[[list 1],[list 2], [list 3]] 我想要一个没有迷你列表的大列表。 @AlexDavies list(itertools.chain.from_iterable([list(group)[2:-2] for group in mit.consecutive_groups(indices_to_remove)])) , import itertools first【参考方案3】:

不用复杂,你可以像这样简单地解决它:

def chunk_lists_(data_):

    consecutive_list = []

    for chunks in range(len(data_)):

        try:

            #check consecutiveness
            if data_[chunks + 1] - data_[chunks] == 1:

                #check if it's already in list
                if data_[chunks] not in consecutive_list:
                    consecutive_list.append(data_[chunks])

                #add last one too
                consecutive_list.append(data_[chunks + 1])

            else:

                #yield here and empty list
                yield consecutive_list
                consecutive_list = []
        except Exception:
            pass
    yield consecutive_list

测试:

#Stephen's list 
print(list(chunk_lists_(list(range(0, 11)) +
        list(range(80, 91)) +
        list(range(160, 171)))))

输出:

[[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90], [160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170]]

【讨论】:

以上是关于如何将列表中的连续元素拆分为子列表的主要内容,如果未能解决你的问题,请参考以下文章

如何通过对flutter中的元素求和来拆分列表

如何对数组中的连续整数进行分组?

Python:根据索引范围将列表拆分为子列表

根据唯一值将列表拆分为子列表

Python 在给定的开始/结束关键字处将列表拆分为子列表

如何在由前一个元素的连续值和第二项中的零组成的列表中添加连续元素?