使用包含分区号的列表对列表项进行分区

Partition a list items using a list containing partition numbers

给定一个列表

lst=['a','a','b','b','b','c','d','d']

和包含分区号的列表'l'

l=[2,3,1,2]

我想要的是

partitioned_lst=[['a','a'],['b','b','b'],['c'],['d','d']]
partitioned_lst=[]
i=0
for n in l:
    partitioned_lst.append(lst[i:i+n])
    i+=n
partitioned_lst

一个班轮只是为了好玩

print([lst[sum(l[:index]):sum(l[:index])+num] for index, num in enumerate(l)])

如果您不能使用 groupby(请参阅 Peter Wood 的评论)因为您需要 l:

lst=['a','a','b','b','b','c','d','d']
l=[2,3,1,2]

it = iter(lst)
result = [[next(it) for _ in range(n)] for n in l]
lst=['a','a','b','b','b','c','d','d']
l=[2,3,1,2]
s = 0
Res=[]
for i in l:
  Res.append(lst[s: s+i])
  s += i
print(Res)

输出

[['a', 'a'], ['b', 'b', 'b'], ['c'], ['d', 'd']]

为了好玩,这里有一个使用相对较新的 assignment expressions (python ≥ 3.8) 的解决方案:

x=0
partitioned_lst = [lst[x:(x:=x+y)] for y in l]

注意。我不会在生产代码中使用它,因为它取决于外部范围

输出:

[['a', 'a'], ['b', 'b', 'b'], ['c'], ['d', 'd']]

这是一个适用于任意迭代的方法:

>>> from itertools import islice
>>> [list(islice(it, n)) for it in [iter(lst)] for n in l]
[['a', 'a'], ['b', 'b', 'b'], ['c'], ['d', 'd']]
>>>

虽然,作为发电机可能会更清洁:

def partition_by(iterable, partitions):
    it = iter(iterable)
    for n in partitions:
        yield list(islice(it, n))

并像这样使用:

>>> list(partition_by(lst, l))
[['a', 'a'], ['b', 'b', 'b'], ['c'], ['d', 'd']]

注意,如果迭代器耗尽,这种方法不会出错并继续:

>>> list(partition_by(lst, [10, 10, 10]))
[['a', 'a', 'b', 'b', 'b', 'c', 'd', 'd'], [], []]

如果这种行为是不可取的:

def partition_by(iterable, partitions, strict=True):
    it = iter(iterable)
    for n in partitions:
        part = list(islice(it, n))
        if not part and strict:
            raise ValueError("iterable ran out of items early")
        yield part

会做的。

类型注释:

import typing
from collections.abc import Iterable

def partition_by(
    iterable: Iterable[T], 
    partitions: Iterable[int], 
    strict: bool=True
) -> Iterable[list[T]]:
    it = iter(iterable)
    for n in partitions:
        part = list(islice(it, n))
        if not part and strict:
            raise ValueError("iterable ran out of items early")
        yield part