'chunk list of objects by property sum

I want to chunk a list of objects in order that the sum of a property is less than a value, let say 10.

lst = [{"value": 1}, {"value": 8}, {"value": 2}, {"value": 6}, {"value": 1}, {"value": 9}, {"value": 10}]

result = [[{"value": 1}, {"value": 8}], [{"value": 2}, {"value": 6}, {"value": 1}], [{"value": 9}], [{"value": 10}]]

This is what I tried so far:

def chunks_by_prop_sum(lst, prop, max_per_chunk):
    chunks = []
    chunk_prop_sum = 0
    chunk = []
    for i in range(0, len(lst)):
        if chunk_prop_sum <= max_per_chunk- lst[i][prop]
            chunk.append(lst[i])
            chunk_prop_sum += lst[i][prop]
        else:
            chunks.append(chunk.copy())
            chunk = []
            chunk_prop_sum = 0

    return chunks

I would like to improve that function by making a generator if possible and also to handle when an object value is greater than the max per chunk threshold.

The order of objects in chunks matter.



Solution 1:[1]

This is building a generator, but also without using any if statements and not a lot of code.

from collections import defaultdict

def chunks_by_prop_sum(data:list[dict], prop:str, max_per_chunk:int) -> list[list[dict]]:
    res = defaultdict(list)
    total, inc = 0, 0
    for entry in data:
        total += entry[prop]
        res[(total // max_per_chunk) + inc].append(entry)
        inc += int(entry[prop] >=  max_per_chunk)
    return list(res.values())

print(chunks_by_prop_sum(lst, 'value', 10))

Solution 2:[2]

There is another option. It is quite neat:

def chunks_by_prop_sum(lst, prop, max_per_chunk):
    out = []
    cum = 0
    for item in lst:
        if out and cum + item[prop] > max_per_chunk:
            yield out
            out = []
            cum = 0
        out.append(item)
        cum += item[prop]
    yield out
    
rv = list(chunks_by_prop_sum(lst, "value", 10))
print(rv == result)

Output:

True

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 azelcer