将列表分成不均匀的组?

Posted

技术标签:

【中文标题】将列表分成不均匀的组?【英文标题】:Splitting a list into uneven groups? 【发布时间】:2016-12-16 03:10:39 【问题描述】:

我知道如何将列表拆分为偶数组,但我无法将其拆分为不均匀的组。

基本上这就是我所拥有的:一些列表,我们称之为mylist,其中包含 x 个元素。

我还有另一个文件,我们称之为 second_list,看起来像这样:

2, 4, 5, 9, etc.

现在我要做的是通过 second_list 中的间距将mylist 分成不均匀的组。所以,我希望我的第一组是mylist 的前两个元素,第二组是mylist 的下四个元素,第三组是mylist 的下五个元素,第四组是成为 `mylist 的下 9 个元素,依此类推。

有没有一些简单的方法可以做到这一点?如果您想将其分成偶数组,我尝试做类似的事情:

for j in range(0, len(second_list)):
    for i in range(0, len(mylist), second_list[j]):
        chunk_mylist = mylist[i:i+second_list[j]]

但是,这并没有像我想要的那样拆分它。我希望我的子列表数量为len(second_list),并且拆分正确,这提供了更多信息(并且拆分不正确)。

【问题讨论】:

如果列表中的元素用完会怎样? 【参考方案1】:

Padraic 拥有最好的 IMO 解决方案,但我会用这个不需要导入的 hacky 单线来补充:

>>> L = [1,2,3,4,5,6,7,8,9,10] # source list - could be any iterable
>>> S = [2,3,4] # group sizes - could be any iterable

>>> [ [ [ next(i) for k in range(j) ] for j in iter(S) ] for i in [iter(L)] ][0]
[[1, 2], [3, 4, 5], [6, 7, 8, 9]]

【讨论】:

【参考方案2】:

将列表理解与切片和sum() 函数一起使用(python 的所有基本和内置工具):

mylist = [1,2,3,4,5,6,7,8,9,10]
seclist = [2,4,6]

[mylist[sum(seclist[:i]):sum(seclist[:i+1])] for i in range(len(seclist))]

#output:
[[1, 2], [3, 4, 5, 6], [7, 8, 9, 10]]

如果seclist 很长,并且您希望更高效,请先使用numpy.cumsum()

import numpy as np
cumlist = np.hstack((0, np.cumsum(seclist)))
[mylist[cumlist[i]:cumlist[i+1]] for i in range(len(cumlist)-1)]

得到同样的结果

【讨论】:

这也是我最初的解决方案,但我认为必须有比计算 2*len(seclist) 总和更有效的方法。 @jedwards 如果担心效率,可以先构建cumulative sum list 是的,这就是我要去的地方 -- seps = [sum(seclist[:i]) for i in range(len(seclist)+1)]; lists = [mylist[i:j] for (i,j) in zip(seps, seps[1:])]【参考方案3】:

numpythonic 方法:

>>> lst = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
>>> sec = [2, 4, 5]
>>> np.split(lst, np.cumsum(sec))
[array([0, 1]), array([2, 3, 4, 5]), array([ 6,  7,  8,  9, 10]), array([11])]

这是一个使用itertool.accumulate()的Python3.X方法:

>>> lst = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
>>> sec = [2,4,6]
>>> from itertools import accumulate
>>> sec = list(accumulate(sec_lst))
>>> sec = [0] + sec + [None] if sec[0] != 0 else sec + [None]
>>> 
>>> [lst[i:j] for i, j in zip(sec, sec[1:])]
[[0, 1], [2, 3, 4, 5], [6, 7, 8, 9, 10], [11]]

【讨论】:

【参考方案4】:

你可以创建一个迭代器和itertools.islice:

mylist = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
seclist = [2,4,6]

from itertools import islice
it = iter(mylist)

sliced =[list(islice(it, 0, i)) for i in seclist]

这会给你:

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

一旦 i 元素被消耗,它们就消失了,所以我们继续获取下一个 i 元素。

不确定剩下的元素会发生什么,如果你想添加它们,你可以添加如下内容:

mylist = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 ,14]
seclist = [2, 4, 6]

from itertools import islice

it = iter(mylist)

slices = [sli for sli in (list(islice(it, 0, i)) for i in seclist)]
remaining = list(it)
if remaining:
    slices.append(remaining)
print(slices)

这会给你:

 [[1, 2], [3, 4, 5, 6], [7, 8, 9, 10, 11, 12], [13, 14]]

或者相反,如果没有足够的,您可以使用几种方法来删除空列表,一种是内部生成器表达式:

from itertools import islice

it = iter(mylist)
slices = [sli for sli in (list(islice(it, 0, i)) for i in seclist) if sli]

或者结合itertools.takewhile:

 from itertools import islice, takewhile

it = iter(mylist)
slices = list(takewhile(bool, (list(islice(it, 0, i)) for i in seclist)))

为:

mylist = [1, 2, 3, 4, 5, 6]
seclist = [2, 4, 6,8]

会给你:

[[1, 2], [3, 4, 5, 6]]

相对于:

[[1, 2], [3, 4, 5, 6], [], []]

您使用什么完全取决于您可能的输入输出以及您希望如何处理各种可能性。

【讨论】:

很好地使用了islice——从同一个迭代器消耗不同数量的项目。 +1 希望我能投票两次;这么一个非常有用的答案,我把它放到了我的个人通用工具库中。【参考方案5】:
subgroups = []
start=0
for i in second_list:
  subgroups.append(mylist[start:start + i])
  start = i + start

最后subgroups 将包含所需的列表

示例运行:

>>> mylist = [1,2,3,4,5,6,7,8,9,10,11,12]
>>> second_list = [2,4,5,9]
>>> subgroups = []
>>> start=0
>>> for i in second_list:
...    subgroups.append(mylist[start:start + i])
...    start = i + start
...
>>> subgroups
[[1, 2], [3, 4, 5, 6], [7, 8, 9, 10, 11], [12]]

【讨论】:

【参考方案6】:

此解决方案会跟踪您编写的项目数量。如果second_list中的数字总和大于mylist会崩溃

total = 0
listChunks = []
for j in range(len(second_list)):
    chunk_mylist = mylist[total:total+second_list[j]]
    listChunks.append(chunk_mylist)
    total += second_list[j]

运行此程序后,listChunks 是一个列表,其中包含在 second_list 中找到的长度的子列表。

【讨论】:

@J.P.,你能分享一下你的second_list 是什么样子的吗?这段代码在我的测试用例中运行良好。 让我仔细检查我的数据(我的列表真的很长)并确保 - 这对我来说是一个问题,在这种情况下我认为这会起作用!我会仔细检查并接受你的回答。谢谢!

以上是关于将列表分成不均匀的组?的主要内容,如果未能解决你的问题,请参考以下文章

映射两个长度不均匀的列表 - 方案

归并排序算法优化

对具有不均匀空格的空格分隔列表进行排序

python 将列表拆分为大小均匀的块

均匀分布的列表项

基于距离的大小为 2 的组