2

I have a bunch of files to iterate over to find the best combination, and would like some advice on how to do it. I have to put together a mixed-age "relay" team. We need (exactly) one person from each age. But, we have a max weight that we can't go over. We know roughly how much each person will score -- the highest total score wins.

I have all the peeps in files by their age with their name, weight and score, eg the 5.csv file has all the 5yr olds (name,weight,score)

JonnyM,54,20
SallyR,35,18
MeganP,33,25
...

the 6.csv has the 6yr olds with the same format

DaveL,53,30
NancyP,40,28
...

etc up to 20.csv.

I suppose I could do this with a lot of typing:

import csv
maxweight=5000
bestscore=0
bestcombo=[]
f5 = csv.reader(open("5.csv", "r"), delimiter=',')
f6 = csv.reader(open("6.csv", "r"), delimiter=',')
...
f20 = csv.reader(open("20.csv", "r"), delimiter=',')
for name5,weight5,score5 in 5f:
    for name6,weight6,score6 in 6f:
...
    ...(and a lot more)
        for name20,weight20,score20 in 20f:
            if((weight5+weight6+...weight20)<=maxweight):
                if((score5+score6+...score20)>bestscore):
                    bestcombo=[name5,name6,...name20]

But, there has got to be a better way. I'm sure its obvious, but I'm also pretty new to python.

1
  • Could you please upload an example csv file and write a complete source code? A simple strategy based on stated assumptions would be to have 2 copies of the list of participants. These lists need to sorted by weight one ascending and one descending. Iterate through both list together until you reach expected total weight range. After which eliminate where either age criteria is not met or same person is showing in the pair. Commented Jul 22, 2019 at 1:41

2 Answers 2

4

You can use itertools.product. You should also use contextlib.ExitStack to close your files:

from contextlib import ExitStack
import csv
import itertools

maxweight = 5000
bestscore = 0
bestcombo = []

with ExitStack() as stack:
    files = [csv.reader(stack.enter_context(open("{}.csv".format(i))), delimiter=',') for i in range(5, 21)]
    for combo in itertools.product(*files):
        names, weight_list, score_list = zip(*combo)
        weight = sum(map(int, weight_list))
        score = sum(map(int, score_list))
        if weight <= maxweight and score > bestscore:
            bestcombo = names
            bestscore = score

This is untested (because I don't have access to the files and am also too lazy too synthesize valid dummy data), so let me know if something errors. Also, this approach is fairly naive and therefore computationally expensive.

Sign up to request clarification or add additional context in comments.

3 Comments

added the last line (else bestscore remains 0)
This is awesome. Had never head of ExitStack or itertools before. I have some more searching to do to fully grok what's going on!
@MilesLibbey If you would like me to add some comments to the code, let me know.
2

Here is a solution, have left enough comments for easy understanding. You can replace hardcoded lists of data with file based reading

import itertools
from functools import reduce

MAX_WEIGHT = 100

#You can read data from files in for loop
csv5 = [('JonnyM',54,20), ('SallyR',35,18), ('MeganP',33,25)]
csv6 = [('HansM',18,20), ('JohnD',35,18)]
csv7 = [('MatG',30,25), ('BossT',36,26)]

args = []
for i in range(5, 8):
    exec('args.append(csv%s)'%i)

result = []
#get cartesian product of these lists
for combinedList in itertools.product(*args):
    #only those that are below the MAX_WEIGHT could be part of solution
    if reduce(lambda a, b: a+b, [e[1] 
        for e in combinedList], 0) <= MAX_WEIGHT:
        result.append(combinedList)

result.sort(key=lambda x: 
        reduce(lambda a, b:a+b, [e[2] for e in x], 0), 
        reverse=True)       

#for r in result:       
#   print(r)

#First element will have max score hence the solution       
print('Desired Solution:' )
print(result[0] )

1 Comment

Thanks! This is awesome. Its nice to have all the results sorted!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.