3

我已经尝试寻找解决方案,但我对精确术语的无知无济于事,希望问题的标题和下面的代码足以解释。

这是我到目前为止的工作:

C = [1,1,1,1,2,3,1,1,1,2,1]
sub_C = []
chunked_C = []
counter = 0
for i in C:
    counter += i
    if counter <= 3:
        sub_C.append(i)
    else:
        chunked_C.append(list(sub_C))
        del sub_C[:]
        counter = i
        sub_C.append(i)
print chunked_C

我希望 chunked_C 产生: [[1,1,1],[1,2],[3],[1,1,1],[2,1]]

不知道我哪里出错了,也许有人可以帮忙。

编辑:我已经纠正了错别字。

还:

稍微修改一下,我也需要对列表的不完整尾部进行分块,即值小于 3 但我用完了数字。

例如:

C = [1,1,1,1,2,3,1,1,1,2,1,1]
so chunked_C = [[1,1,1],[1,2],[3],[1,1,1],[2,1],[1]]

希望这是有道理的。

进一步修订:

如果 C = [1,1,1,1,1,2,3,1,1,1,2,1]

chunked_C 将等于 [[1,1,1],[1,1],[2],[3],[1,1,1],[2,1]]

所以我想逻辑需要进一步修改。

4

7 回答 7

6

编辑:首先,正如 Ashwini 在评论中指出的那样,我们需要确保释放最后一个块,即使它没有达到目标。

也就是说,使用以下方法可以更好地解决此问题itertools.groupby()

import itertools

c = [1,1,1,1,2,3,1,1,1,2,1]

class group_by_sum:
    def __init__(self, target):
        self.target = 3
        self.current = False
        self.sum = 0

    def __call__(self, item):
        self.sum += item
        if self.sum > self.target:
            self.sum = item
            self.current = not self.current
        return self.current

    def group(self, iterable):
        return [tuple(items) for _, items in itertools.groupby(iterable, self)]

>>> group_by_sum(3).group(c)

[(1, 1, 1), (1, 2), (3,), (1, 1, 1), (2, 1)]

显然,最后的便利方法不一定重要,但它使使用更简单。


老答案:

这可以用生成器很好地完成:

def chunk_to_sum(iterable, target):
    chunk_sum = 0
    chunk = []
    for item in iterable:
        chunk_sum += item
        if chunk_sum > target:
            yield chunk
            chunk = [item]
            chunk_sum = item
        else:
            chunk.append(item)
    if chunk: yield chunk

>>> list(chunk_to_sum([1, 1, 1, 1, 2, 3, 1, 1, 1, 2, 1], 3))
[[1, 1, 1], [1, 2], [3], [1, 1, 1], [2, 1]]
于 2013-08-30T16:01:30.863 回答
1

我认为“if counter < 3:”这一行是您想要的向后逻辑。这是我写的更正版本:

def chunk(to_chunk, n):
    """ 
    >>> chunk([1,1,1,1,2,3,1,1,1,2,1], 3) 
    [[1, 1, 1], [1, 2], [3], [1, 1, 1], [2, 1]]
    """

    result, accum, total = [], [], 0

    for i in to_chunk:
        accum.append(i)

        if total + i >= n:
            result.append(accum)
            accum, total = [], 0
        else:
            total += i

    return result
于 2013-08-30T15:59:41.340 回答
1

是的,我想你想使用发电机。这只是对 Lattyware 版本的轻微清理。(去投票给他)

def chunk_to_sum(items, target_value):
    chunk = []
    for item in items:
        chunk.append(item)
        if sum(chunk) >= target_value:
            yield chunk
            chunk = []


C = [1,1,1,1,2,3,1,1,1,2,1,1]
list(chunk_to_sum(C, 3))

输出[2]:[[1, 1, 1], [1, 2], [3], [1, 1, 1], [2, 1]]

于 2013-08-30T16:50:10.240 回答
0

由于未知原因,程序忽略了列表中的最后一个整数,所以这里有一个固定版本,只是将一个整数添加到列表中,所以它会忽略它并正确处理其余的

C = [1,1,1,1,2,3,1,1,1,2,1,1]
sub_C = []
chunked_C = []
counter = 0
for i in C:
    counter += i
    if counter <= 3:
        sub_C.append(i)
    else:
        chunked_C.append(list(sub_C))
        del sub_C[:]
        counter = i
        sub_C.append(i)
print chunked_C

产生:

[[1, 1, 1], [1, 2], [3], [1, 1, 1], [2, 1]]
于 2013-08-30T15:57:06.170 回答
0

你可以在这里使用迭代器,这里不需要额外的列表:

def solve(lis, chunk_size):
    it = iter(lis)
    first = next(it)
    chunked_C = [[first]]
    counter = first
    for i in it:
        if counter + i < chunk_size:
            chunked_C[-1].append(i)
            counter += i
        else:
            chunked_C.append([i])
            counter = i 
    return  chunked_C
print solve([1,1,1,1,2,3,1,1,1,2,1], 4)
print solve([1,1,1,1,1,2,3,1,1,1,2,1], 4)

输出:

[[1, 1, 1], [1, 2], [3], [1, 1, 1], [2, 1]]
[[1, 1, 1], [1, 1], [2], [3], [1, 1, 1], [2, 1]]

使用生成器函数:

def solve(lis, chunk_size):
    chunk = []
    counter = 0
    for i in lis:
        if counter + i < chunk_size:
            chunk.append(i)
            counter += i
        else:
            yield chunk
            chunk = [i]
            counter = i
    if chunk: yield chunk

print list(solve([1,1,1,1,2,3,1,1,1,2,1], 4))
print list(solve([1,1,1,1,1,2,3,1,1,1,2,1], 4))

输出:

[[1, 1, 1], [1, 2], [3], [1, 1, 1], [2, 1]]
[[1, 1, 1], [1, 1], [2], [3], [1, 1, 1], [2, 1]]
于 2013-08-30T16:00:07.293 回答
0

试试这个:

def get_subsection_from_index(l, index):
    subsection = []
    while sum(subsection) < 3:
        if index < len(l):
            subsection.append(l[index])
        else:
            break
        index += 1
    return subsection, index

i = 0
chunked_C = []
while i < len(C):
    subsection, i = get_subsection_from_index(C, i)
    chunked_C.append(subsection)
于 2013-08-30T16:00:38.230 回答
0

两个嵌套的while循环怎么样:

C = [1,1,1,1,2,3,1,1,1,2,1]
out=[]
while C:
    temp=[C.pop(0)]
    while C and sum(temp) <3:
        temp.append(C.pop(0))
    out.append(temp)    

print out    
# [[1, 1, 1], [1, 2], [3], [1, 1, 1], [2, 1]]

如果性能很重要,请使用双端队列而不是列表:

from collections import deque

C = [1,1,1,1,2,3,1,1,1,2,1]
Cd=deque(C)
out=[]
while Cd:
    temp=[Cd.popleft()]
    while Cd and sum(temp) <3:
        temp.append(Cd.popleft())
    out.append(temp)    

或者,使用类似的逻辑并转换为生成器:

def gen_chunks(it,n):
    try:
        while it:
            ck=[]
            while sum(ck)<n:
                ck.append(next(it))
            yield ck
    except StopIteration:
       pass 

print list(gen_chunks(iter(C),3))
# [[1, 1, 1], [1, 2], [3], [1, 1, 1], [2, 1]]

如果你想使用不加起来的“面包屑”,n很容易添加:

def gen_chunks(it,n, return_crumbs=False):
    ck=[]
    try:
        while it:
            if sum(ck)>=n:
                yield ck
                ck=[]
            else:
                ck.append(next(it))
    except StopIteration:
        if return_crumbs and ck:
            yield ck

print list(gen_chunks(iter(C),3))
print list(gen_chunks(iter(C),3,True))
# [[1, 1, 1], [1, 2], [3], [1, 1, 1], [2, 1]]        no crumbs
# [[1, 1, 1], [1, 2], [3], [1, 1, 1], [2, 1], [1]]   with crumbs
#                                             ^^^      crumb
于 2013-08-30T16:08:37.267 回答