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