如何将数字列表中的每个块的总和小于n?

时间:2013-08-30 15:45:29

标签: python

我已经尝试过寻找解决方案,但是我对精确术语的无知并没有帮助,希望问题的标题和下面的代码是足够的解释。

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

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但我的数字用完了。

e.g:

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]]

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

7 个答案:

答案 0 :(得分: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]]

答案 1 :(得分:1)

我认为“if counter&lt; 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

答案 2 :(得分: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]]

答案 3 :(得分: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]]

答案 4 :(得分: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]]

答案 5 :(得分: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)

答案 6 :(得分: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]]

如果效果很重要,请使用deque代替列表:

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