Calculating a score that increases, at variable rate, based on number of items in a list

Question:

My assignment:

The program should give you 1 point for EACH of the first twenty items in the list(refers to the items in the list – software_uses), 0.5 points for the next 10 items, 0.25 points for the next 10 items, etc. (each additional 10 items scores 1/2 the points as the previous 10 items).

The total score should be rounded down to the next lower integer (use the int() function).
It has to print the maximum possible score.

  • using variables total_items and total_score

I’m struggling where to go off from what I have. The description above shows that the number points given for each of the first twenty items is a what if. Perhaps I need to use a if statement?

software_uses = ["Checking email", "Mapping directions", "Checking the weather", "Academic Uses", "Purchasing Goods", "Ask for Help", "Social Media", "Work", "Transportation", "Banking"]

total_items=len(software_uses)
total_score=0

#if total_items

print(f"Total Items: {total_items}, Total Score: {total_score}")
Asked By: Axel Palomino

||

Answers:

from typing import Union
total_items = [[]] * 50
total_score = 0
score_increment = 1

# recursive accumulation function definition
def accumulate_recurse(items : list, score_per_item : Union[float|int]) -> float:
    # recursive case
    if len(items) > 10:
        return (10 * score_per_item) + accumulate_recurse(items[10:], (score_per_item / 2))
    # base/halting case
    else:
        return len(items) * score_per_item

# recurse if initial conditional logic isn't met     
if len(total_items) > 20:
    total_score += 20 +  accumulate_recurse(total_items[20:],  (score_increment / 2))

# basic arithmetic if no recursion is necessary
else:
    total_score += len(total_items) * score_increment

This should work, but I’m writing this on my phone, so my debugging options are limited. Use this as a starting point and modify it to your needs.

Edit: refactored it to make conditional logic look better. Doesn’t take into consideration all of his requirements but assuming that this is probably his homework for the night, I’m not gonna take his course for him.

Answered By: Carter Canedy

It might help to solve this in a more mathsy way. Imagine you are trying to come up with a line-equation for a line that graphs the score for any given index in your list of items. The x-axis would be your item indices, and the y-axis would be the corresponding scores.

Let’s simplify the requirements initially – let’s ignore the whole business of "the first twenty…" and "the next ten…". Let’s just say the first score should be 1.0, the second score should be 0.5, the third 0.25, etc. The pattern here is pretty simple. The score starts at 1.0, and gets divided in half each single "step" we take.

The first few points that make up this line would be (0.0, 1.0), (1.0, 0.5), (2.0, 0.25) and (3.0, 0.125).
Another way of writing this would be (0.0, 1.0 / 1), (1.0, 1.0 / 2), (2.0, 1.0 / 4) and (3.0, 1.0 / 8). The pattern here is that, for each "step", the next y-value will be one over the next power of two (2**0==1, 2**1==2, 2**2==4 and 2**3==8.)

The equation for this line would therefore be: y = 1.0 / (2 ** x):


Let’s reintroduce one of the requirements: The score must be cut in half for every ten "steps".

Easy. Just make x increase ten times more slowly: y = 1.0 / (2 ** (x // 10)).
Note: // means integer division, so that we’re raising 2 to the power of an integer, not a floating-point number. This is equivalent to int(x / 10).


Final requirement: The first twenty items must have a score of 1.0. Starting at item# 21, the score gets cut in half every ten "steps", starting at 0.5.
You can think of this as a piece-wise function, where the function always yields 1.0 if x <= 20, otherwise it yields the computed value from our line-equation. With one small difference: We need to subtract 1 from the exponent so that our pattern starts at 0.5 at item# 21 rather than 0.25. This is because 2 ** (20 // 10) == 2 ** 2 == 4, whereas 2 ** ((20 // 10) - 1) == 2 ** (2 - 1) == 2 ** 1 == 2. Note: Item# 21 has an index of 20, since the first item has an index of 0.

In Python, you could define a function that takes an index as a parameter, and returns the corresponding score for that index:

items = ["a", "b", "c", "d", "e"] * 12 # Some items...

def get_index_score(index):
    threshold = 20
    return 1.0 if index < threshold else 1 / (2 ** ((index // 10) - 1))

total_score = sum(get_index_score(index) for index, _ in enumerate(items))

print(f"Total score for {len(items)} items: {total_score}")

for index, item in enumerate(items):
    score = get_index_score(index)
    print(f"[{index}]: {item} => {score}")

Output:

Total score for 60 items: 29.375
[0]: a => 1.0
[1]: b => 1.0
[2]: c => 1.0
[3]: d => 1.0
[4]: e => 1.0
[5]: a => 1.0
[6]: b => 1.0
[7]: c => 1.0
[8]: d => 1.0
[9]: e => 1.0
[10]: a => 1.0
[11]: b => 1.0
[12]: c => 1.0
[13]: d => 1.0
[14]: e => 1.0
[15]: a => 1.0
[16]: b => 1.0
[17]: c => 1.0
[18]: d => 1.0
[19]: e => 1.0
[20]: a => 0.5
[21]: b => 0.5
[22]: c => 0.5
[23]: d => 0.5
[24]: e => 0.5
[25]: a => 0.5
[26]: b => 0.5
[27]: c => 0.5
[28]: d => 0.5
[29]: e => 0.5
[30]: a => 0.25
[31]: b => 0.25
[32]: c => 0.25
[33]: d => 0.25
[34]: e => 0.25
[35]: a => 0.25
[36]: b => 0.25
[37]: c => 0.25
[38]: d => 0.25
[39]: e => 0.25
[40]: a => 0.125
[41]: b => 0.125
[42]: c => 0.125
[43]: d => 0.125
[44]: e => 0.125
[45]: a => 0.125
[46]: b => 0.125
[47]: c => 0.125
[48]: d => 0.125
[49]: e => 0.125
[50]: a => 0.0625
[51]: b => 0.0625
[52]: c => 0.0625
[53]: d => 0.0625
[54]: e => 0.0625
[55]: a => 0.0625
[56]: b => 0.0625
[57]: c => 0.0625
[58]: d => 0.0625
[59]: e => 0.0625
Answered By: Paul M.
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.