From 725f977bf5a3218de2b8592d3c9fd80532c0c09a Mon Sep 17 00:00:00 2001 From: Michael Morehouse <640167+yawpitch@users.noreply.github.com> Date: Thu, 13 Feb 2020 16:36:29 +0000 Subject: [PATCH] [book-store] Simplify example.py The existing example.py is quite complex and not particulary efficient, even for quite small lists of books. This example.py is much simpler, but could be made considerably more efficient through a bit of a caching and some sensible short-circuit returns. These are left to the student to figure out, however. --- exercises/book-store/example.py | 75 +++++++++++---------------------- 1 file changed, 25 insertions(+), 50 deletions(-) diff --git a/exercises/book-store/example.py b/exercises/book-store/example.py index 4236656ada..a9d0054b11 100644 --- a/exercises/book-store/example.py +++ b/exercises/book-store/example.py @@ -1,51 +1,26 @@ -from functools import reduce - -BASE_COST = 800 -discount = [1.0, 1.0, 0.95, 0.9, 0.8, 0.75] - - -def group_cost(group): - return len(group) * discount[len(group)] - - -class Grouping: - def __init__(self, groups=None): - self.groups = [set()] if groups is None else groups - - def total(self): - return sum(map(group_cost, self.groups)) * BASE_COST - - def dup(self): - return Grouping(list(map(set, self.groups))) - - def add_to_valid(self, book): - """Returns all possible groupings from the - current grouping adding book - """ - other = self.dup() - other.groups.sort(key=lambda g: len(g)) - results = [] - for index, group in enumerate(other.groups): - if book not in group: - other2 = other.dup() - other2.groups[index].add(book) - results.append(other2) - if not results: - other.groups.append(set([book])) - return [other] - return results - - def __lt__(self, other): - return self.total() < other.total() - - -def step(basket, book): - return [group for groupings in basket - for group in groupings.add_to_valid(book)] - - -def total(basket): - if len(basket) == 0: +from collections import Counter + +PER_BOOK = 800.00 +PER_GROUP = { + 1: 1 * PER_BOOK * 1.00, + 2: 2 * PER_BOOK * 0.95, + 3: 3 * PER_BOOK * 0.90, + 4: 4 * PER_BOOK * 0.80, + 5: 5 * PER_BOOK * 0.75, +} + + +def _total(books): + volumes = Counter(books) + price = len(books) * PER_BOOK + for size in range(len(volumes), 1, -1): + group = volumes - Counter(k for k, _ in volumes.most_common(size)) + group_books = sorted(group.elements()) + price = min(price, PER_GROUP[size] + _total(group_books)) + return price + + +def total(books): + if not books: return 0 - start = Grouping([{basket[0]}]) - return round(min(reduce(step, basket[1:], [start])).total()) + return _total(sorted(books))