The first item of the returned list ("lb") has the leftover.
IMO, procedural paradigm (in general) is easier to read and debug.
(BTW, this is my first attempt to answer at SO)
items = {'Apple': 1, 'Pear': 3, 'Orange': 2, 'Banana' : 4, 'Grape' : 3, 'Melon': 5, 'Lemon': 1}
budget = 10
import itertools
lk = list(items.keys()) # List of Keys
ltf = list(itertools.combinations(lk, 4)) # List of Tuples of Fruits
# Procedural
lb = [] # List under Budget
for tf in ltf:
s = 0
for f in tf:
s += items[f]
print(s, tf)
if s <= budget:
lb.append((budget - s, tf)) # Leftover, Tuple of Fruit
print('Under budget\n')
A more functional code (with leftover).
(The one-liner answer of @ilyankou is more elegant):
ls_tf = [(sum([items[f] for f in tf]), tf) for tf in ltf]
lb = [(budget - s_tf[0], s_tf[1]) for s_tf in ls_tf if (s_tf[0] <= budget)]
Out (procedural and functional):
[(0, ('Apple', 'Pear', 'Orange', 'Banana')),
(1, ('Apple', 'Pear', 'Orange', 'Grape')),
(3, ('Apple', 'Pear', 'Orange', 'Lemon')),
(1, ('Apple', 'Pear', 'Banana', 'Lemon')),
(2, ('Apple', 'Pear', 'Grape', 'Lemon')),
(0, ('Apple', 'Pear', 'Melon', 'Lemon')),
(0, ('Apple', 'Orange', 'Banana', 'Grape')),
(2, ('Apple', 'Orange', 'Banana', 'Lemon')),
(3, ('Apple', 'Orange', 'Grape', 'Lemon')),
(1, ('Apple', 'Orange', 'Melon', 'Lemon')),
(1, ('Apple', 'Banana', 'Grape', 'Lemon')),
(0, ('Apple', 'Grape', 'Melon', 'Lemon')),
(0, ('Pear', 'Orange', 'Banana', 'Lemon')),
(1, ('Pear', 'Orange', 'Grape', 'Lemon')),
(0, ('Orange', 'Banana', 'Grape', 'Lemon'))]
Print of procedural
10 ('Apple', 'Pear', 'Orange', 'Banana')
Under budget
9 ('Apple', 'Pear', 'Orange', 'Grape')
Under budget
11 ('Apple', 'Pear', 'Orange', 'Melon')
7 ('Apple', 'Pear', 'Orange', 'Lemon')
Under budget
11 ('Apple', 'Pear', 'Banana', 'Grape')
13 ('Apple', 'Pear', 'Banana', 'Melon')
9 ('Apple', 'Pear', 'Banana', 'Lemon')
Under budget
12 ('Apple', 'Pear', 'Grape', 'Melon')
8 ('Apple', 'Pear', 'Grape', 'Lemon')
Under budget
10 ('Apple', 'Pear', 'Melon', 'Lemon')
Under budget
10 ('Apple', 'Orange', 'Banana', 'Grape')
Under budget
12 ('Apple', 'Orange', 'Banana', 'Melon')
8 ('Apple', 'Orange', 'Banana', 'Lemon')
Under budget
11 ('Apple', 'Orange', 'Grape', 'Melon')
7 ('Apple', 'Orange', 'Grape', 'Lemon')
Under budget
9 ('Apple', 'Orange', 'Melon', 'Lemon')
Under budget
13 ('Apple', 'Banana', 'Grape', 'Melon')
9 ('Apple', 'Banana', 'Grape', 'Lemon')
Under budget
11 ('Apple', 'Banana', 'Melon', 'Lemon')
10 ('Apple', 'Grape', 'Melon', 'Lemon')
Under budget
12 ('Pear', 'Orange', 'Banana', 'Grape')
14 ('Pear', 'Orange', 'Banana', 'Melon')
10 ('Pear', 'Orange', 'Banana', 'Lemon')
Under budget
13 ('Pear', 'Orange', 'Grape', 'Melon')
9 ('Pear', 'Orange', 'Grape', 'Lemon')
Under budget
11 ('Pear', 'Orange', 'Melon', 'Lemon')
15 ('Pear', 'Banana', 'Grape', 'Melon')
11 ('Pear', 'Banana', 'Grape', 'Lemon')
13 ('Pear', 'Banana', 'Melon', 'Lemon')
12 ('Pear', 'Grape', 'Melon', 'Lemon')
14 ('Orange', 'Banana', 'Grape', 'Melon')
10 ('Orange', 'Banana', 'Grape', 'Lemon')
Under budget
12 ('Orange', 'Banana', 'Melon', 'Lemon')
11 ('Orange', 'Grape', 'Melon', 'Lemon')
13 ('Banana', 'Grape', 'Melon', 'Lemon')