简体   繁体   中英

Combination sum with Python dict

I have a dict of fantasy football (soccer) data, where the first value in the tuple is a price and the second is an expected points for the season. A segment of it can be seen below:

 'Romeu': [4.5, 57.0],
 'Neves': [5.5, 96.0],
 'Townsend': [6.0, 141.0],
 'Lucas Moura': [7.5, 105.0],
 'Martial': [7.5, 114.0],
 'David Silva': [7.5, 177.0],
 'Fraser': [7.5, 180.0],
 'Richarlison': [8.0, 138.0],
 'Bernardo Silva': [8.0, 174.0],
 'Sigurdsson': [8.0, 187.0],

What I would like to do is write a program that allows me to set a price limit and return the combination of a fixed length eg n=5 which has the maximum score.

So if I set the price limit to 32 and I want 5 players, it returns Romeu, Neves, Townsend, Sigurdsson, Fraser.

Can someone please give me a hint in the right direction? I have no idea how to get started with this.

Here is a brute force approach that I've tried with a selection of 5 players out of 115 (1 minute, 42 seconds on my laptop). Increasing the selection to 20 players out of only 100 will take over 100,000 years to execute. Even 20 of 50 will take 4 days.

from itertools import combinations

# Set the following parameters as desired
nplayers = 5
price = 32

players = {
    'Romeu': [4.5, 57.0],
    'Neves': [5.5, 96.0],
    'Townsend': [6.0, 141.0],
    'Lucas Moura': [7.5, 105.0],
    'Martial': [7.5, 114.0],
    'David Silva': [7.5, 177.0],
    'Fraser': [7.5, 180.0],
    'Richarlison': [8.0, 138.0],
    'Bernardo Silva': [8.0, 174.0],
    'Sigurdsson': [8.0, 187.0],
}

if len(players) < nplayers:
    raise IndexError("You selected {nplayers} players but there are only {len(players)} to choose from")

# Create a list of all combinations of players, store as triples (name, cost, score)
combos = combinations(((h, *t) for h, t in players.items()), nplayers)

top_score = 0

for c in combos:
    if sum(p[1] for p in c) <= price:
        score = sum(p[2] for p in c)
        if score > top_score:
            top_teams = [c]
            continue
        elif score == top_score:
            top_teams.append(c)

if top_score:
    print(top_teams)
else:
    print(f"You can't afford a team for only {price}")

Output

[(('Romeu', 4.5, 57.0), ('Neves', 5.5, 96.0), ('Townsend', 6.0, 141.0), ('Fraser', 7.5, 180.0), ('Sigurdsson', 8.0, 187.0))]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM