We can slightly modify the powerset
recipe from the itertools doumentation to not use an explicit loop:
from itertools import chain, combinations
def powerset(iterable):
"powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"
s = list(iterable)
return chain.from_iterable(map(lambda r: combinations(s, r), range(len(s)+1)))
For each combination of luggage, we can filter out all of those that exceed the maximum weight, then take the one with the most items:
def calc_max_baggage(weights, W):
weights = powerset(weights)
filtered = filter(lambda items: sum(items) <= W, weights)
filtered = chain(filtered, ((),))
return max(filtered, key=len)
filtered = chain(filtered, ((),))
is so if W
is negative we return no bags anyways, even though technically the sum of their weights is greater than W
.
This will return the actual set of items, rather than its length, but you can easily convert it.
>>> calc_max_baggage([4, 2, 3, 1], 5)
(4, 1)
>>> calc_max_baggage ([1, 1, 1], 5)
(1, 1, 1)
>>> calc_max_baggage([5], 0)
()
If you need a recursive component, you can define powerset
recursively, though it's markedly less efficient
def powerset(seq):
if not seq:
return ((),)
else:
head, *tail = seq
tail_pow = powerset(tail)
with_head = tuple(map(lambda t: (head,) + t, tail_pow))
return with_head + tail_pow