Reputation:
I've got the following code.
sum_review = reduce(add,[book['rw'] for book in books])
sum_rating = reduce(add,[book['rg'] for book in books])
items = len(books)
avg_review = sum_review/items
avg_rating = sum_rating/items
What I'd like is this.
sum_review,sum_rating = reduce(add,([book['rw'],[book['rg']) for book in books])
items = len(books)
avg_review = sum_review/items
avg_rating = sum_rating/items
Obviously this doesn't work. How can I solve this redundancy, without a regular loop?
Upvotes: 3
Views: 3247
Reputation: 67870
There are two typical approaches to simplify code:
Top-down: get the values first and then transpose them with zip(*iterable)
. It's also cool because it only iterates the collection once:
values = ((book["rw"], book["rg"]) for book in books)
avg_review, avg_rating = [sum(xs) / len(books) for xs in zip(*values)]
Bottom-up: create a function to abstract the operation:
get_avg = lambda xs, attr: sum(x[attr] for x in xs) / len(xs)
avg_review = get_avg(books, "rw")
avg_rating = get_avg(books, "rg")
Upvotes: 3
Reputation: 45542
You should prefer clarity over optimization. In 3 years of using Python, I have only had to profile to discover performance bottlenecks twice. Your original code is clear and efficient. Compressing the first two lines into one hurts readability and barely impacts performance.
If I had to revise your code, it would like this:
avg_review = sum(book['rw'] for book in books) / len(books)
avg_rating = sum(book['rg'] for book in books) / len(books)
(That's five lines of code down to two with an improvement of clarity.)
Upvotes: 2
Reputation: 61526
How can I solve this redundancy
By making a function, of course:
def average_value(items, key):
values = [x[key] for x in items]
return sum(items) / len(items)
avg_review, avg_rating = average_value(books, 'rw'), average_value(books, 'rg')
Upvotes: 1
Reputation: 838336
I'd avoid using reduce here. For something so simple use sum
:
sum_review = sum(book['rw'] for book in books)
sum_rating = sum(book['rg'] for book in books)
In my opinion this simpler version doesn't need refactoring to remove redundancy. With just two items (rw
and rg
) I think it's best to just leave it as it is.
Upvotes: 9
Reputation: 110311
sum_review, sum_rating = reduce(lambda a,b: (a[0] + b[0], a[1]+b[1]), ((book['rw'], book['rg']) for book in books), (0,0) )
items = len(books)
avg_review = sum_review/items
avg_rating = sum_rating/items
(tested)
Upvotes: 2