Best approach to make a reverse five-star calculator
<p>In the 5-star rating system, I have a known number of ratings.<br>
I have the final (weighted) average of all those N ratings, let's say it is R (float to two decimal places).<br>
I would like to write a python script which generates all possible combinations (Total of weighted averages) and print out only the one(s) which result in R. </p>

<p>How would I approach this problem?</p>

<p><strong>Example:</strong></p>

<p>N= 20 customers rated a product<br>
R = 3.85 is the average rating</p>

<p>Output I am looking for:</p>

<blockquote>
  <p>10 five-stars, 4 four-stars, 1 three-stars, 3 two-stars, and 2 one-star </p>
</blockquote>

<p>is one combination which would give 3.85 by 20 customers.</p>

<p>How would I test if there are any more combinations which could result in the given R and print them out as well? </p>

<p>(inefficient) Brute force solution. </p>

<p>Note: Can make more efficient by replacing <code>product(range(0, N+1), repeat=5)</code> with something else that can generate a list of 5 numbers that sum to N. </p>

<p>Find all lists of length 5 (for the ratings) up to N, then calculate the weighted average and compare against R. Print the lists as you go </p>

<pre><code>from itertools import product

def weighed_avergage(l, total):
    if sum(l) != total:
        return 0
    return sum(rating * stars for rating, stars in zip(l, range(5, 0, -1))) / float(total)

N = 20
R = 3.85

for p in product(range(0, N+1), repeat=5):
    w_avg = weighed_avergage(p, N)
    if w_avg == R:
        print p
</code></pre>

<p>Should see <code>(10, 4, 1, 3, 2)</code> in the output, which corresponds to your question of 10 five-stars, 4 four-stars, 1 three-stars, 3 two-stars, and 2 one-star</p>

python algorithm