Skip to content

Instantly share code, notes, and snippets.

Created February 6, 2015 20:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/4ac489a13ddff3ad2b04 to your computer and use it in GitHub Desktop.
Save anonymous/4ac489a13ddff3ad2b04 to your computer and use it in GitHub Desktop.
from collections import Counter, OrderedDict
from itertools import chain
class Bin(object):
def __init__(self, size):
self.size = size
self.item_sizes = []
@property
def size_used(self):
return sum(self.item_sizes)
def fits(self, additional_size):
return (self.size_used + additional_size) <= self.size
def pack(self, item_size, check=True):
if check and not self.fits(item_size):
raise ValueError('item size does not fit in bin')
self.item_sizes.append(item_size)
class BinDict(OrderedDict):
def __init__(self, bin_sizes, suffix=''):
content = ((size, [Bin(size)]) for size in bin_sizes)
OrderedDict.__init__(self, content)
self._amount_template = '{}x {}' + suffix
def __str__(self):
return '\n'.join(self.iter_formatted_lines())
def iter_formatted_lines(self):
for size, bins in self.items():
item_sizes = list(
chain.from_iterable(bin.item_sizes for bin in bins)
)
if item_sizes:
num_bins = self._amount_template.format(len(bins), size)
content = self.get_formatted_item_sizes(item_sizes)
yield '{} ({})'.format(num_bins, content)
def get_formatted_item_sizes(self, item_sizes):
counter = Counter(item_sizes)
return ', '.join(
self._amount_template.format(amount, item_size)
for item_size, amount in counter.items()
)
def find_bin(needed_size, bin_dict):
for bins in bin_dict.values():
for bin in bins:
if bin.fits(needed_size):
return bin
def get_new_bin(item_size, bin_sizes):
for size in bin_sizes:
if size >= item_size:
return Bin(size)
def get_packed_bins(item_sizes, bin_sizes, suffix=''):
bin_sizes = sorted(bin_sizes)
bin_dict = BinDict(bin_sizes, suffix)
for item_size in sorted(item_sizes, reverse=True):
bin = find_bin(item_size, bin_dict)
if bin is None:
bin = get_new_bin(item_size, bin_sizes)
if bin is None:
msg = 'could not find bin for item size {}'
raise ValueError(msg.format(item_size))
bin_dict[bin.size].append(bin)
bin.pack(item_size, check=False)
return bin_dict
def size_dict_to_list(size_dict):
chained = chain.from_iterable(
[size] * amount for size, amount in size_dict.items()
)
return list(chained)
def find_lumber_combination(lumber_sizes, available_dimensions, suffix='mm'):
item_sizes = size_dict_to_list(lumber_sizes)
return get_packed_bins(item_sizes, available_dimensions, suffix)
def main():
needed_lumber = {1470: 2, 2090: 2, 1354: 2, 1974: 1}
dimensions = [2000, 2500, 3000, 4000]
print(find_lumber_combination(needed_lumber, dimensions))
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment