在Python中读取CSV文件并分配给不同的列表

时间:2017-02-25 02:24:17

标签: python csv

我正在关注一个在线Python项目并遇到一些问题。我不觉得我的代码非常“pythonic”,代码无法正常工作。

该程序应该读取足球运动员的CSV文件。输出意味着将球员分成三个不同的足球队。每支球队应该拥有与足球经验相同数量的球员和相同数量的球员。在18名球员中,有9名有经验,因此相当于六名队员,六名队员中有三名有经验。我可以得到它,所以每支球队有六名球员,但我被绊倒的部分是体验部分。有些团队最终有三个,但有些团队没有。这是我到目前为止所尝试的:

import csv
import random

def assign_players():
    with open('soccer_players.csv') as csvfile:
        soccerplayers = csv.DictReader(csvfile)
        players = list(soccerplayers)

        target = open('teams.txt', 'w')

        raptors=[]
        dragons=[]
        sharks=[]

        for player in players:
            experienced_player = 0
            if len(raptors)<6:
                raptors.append(player)
                if player['Soccer Experience'] == 'YES':
                    experienced_player+=1
                    if experienced_player >3:
                        break

            elif len(dragons)<6:
                dragons.append(player)
                if player['Soccer Experience'] == 'YES':
                    experienced_player+=1
                    if experienced_player >3:
                        break

            else:
                sharks.append(player)
                # if player['Soccer Experience'] == 'YES':
                #     experienced_player+=1
                #     if experienced_player >3:
                #         break

        target.write("Raptors")
        target.write("\n")
        for raptor in raptors:
            target.write(str(raptor["Name"])+ ', '),
            target.write(str(raptor["Soccer Experience"])+ ', '), " ",
            target.write(str(raptor["Guardian Name(s)"])+ ' '), " ",
            target.write("\n")

        target.write("\n")

        target.write("Dragons")
        target.write("\n")
        for dragon in dragons:
            target.write(str(dragon["Name"]) + ', '),
            target.write(str(dragon["Soccer Experience"]) + ', '), " ",
            target.write(str(dragon["Guardian Name(s)"]) + ' '), " ",
            target.write("\n")

        target.write("\n")

        target.write("Sharks")
        target.write("\n")
        for shark in sharks:
            target.write(str(shark["Name"]) + ', '),
            target.write(str(shark["Soccer Experience"]) + ', '), " ",
            target.write(str(shark["Guardian Name(s)"]) + ' '), " ",
            target.write("\n")

if __name__ == "__main__":
     assign_players()

这是关于soccer_players.csv文件格式化的示例

Name,Height (inches),Soccer Experience,Guardian Name(s)
Joe Smith,42,YES,Jim and Jan Smith

2 个答案:

答案 0 :(得分:1)

这是一个适用于任意数量的玩家和团队的解决方案。它随机地随机播放玩家列表,按经验对其进行排序,然后循环将玩家分配给可用的团队:

#!python3
import csv
import random
import itertools
import operator
from collections import namedtuple

Team = namedtuple('Team','name players')

teams = Team('Raptors',[]), Team('Dragons',[]), Team('Sharks',[])

with open('soccer_players.csv', newline='') as csvfile:
    players = list(csv.DictReader(csvfile))

random.shuffle(players)
players.sort(key=operator.itemgetter('Soccer Experience'))

iteam = itertools.cycle(teams)
for player in players:
        next(iteam).players.append(player)

with open('teams.txt', 'w') as target:
    for team in teams:
        target.write(team.name + '\n')
        for player in team.players:
            target.write('{Name}, {Soccer Experience}, {Guardian Name(s)}\n'.format(**player))
        target.write('\n')

输入文件(不是很原始,但没有提供):

Name,Height (inches),Soccer Experience,Guardian Name(s)
A,40,YES,aaa
B,40,YES,bbb
C,40,YES,ccc
D,40,YES,ddd
E,40,YES,eee
F,40,YES,fff
G,40,YES,ggg
H,40,YES,hhh
I,40,YES,iii
J,40,NO,jjj
K,40,NO,kkk
L,40,NO,lll
M,40,NO,mmm
N,40,NO,nnn
O,40,NO,ooo
P,40,NO,ppp
Q,40,NO,qqq
R,40,NO,rrr

输出文件:

Raptors
M, NO, mmm
O, NO, ooo
J, NO, jjj
A, YES, aaa
H, YES, hhh
B, YES, bbb

Dragons
L, NO, lll
N, NO, nnn
P, NO, ppp
C, YES, ccc
I, YES, iii
E, YES, eee

Sharks
R, NO, rrr
Q, NO, qqq
K, NO, kkk
G, YES, ggg
D, YES, ddd
F, YES, fff

答案 1 :(得分:0)

我对该代码的最大担忧是它的具体程度。例如,团队的名称被编码为特定变量,这些变量是单独处理的。球员与球队的分配假设特定数量的球队和可用球员。等等。处理的每一部分仅适用于特定的预期数据。

第二个问题是如何在一个功能中完成所有事情。阅读球员数据,将球员分配给球队,写出球队名单 - 这些都塞满了一个综合功能。

那么,如何改进?首先,让我们更加模块化和通用:

def read_players(filepath):
    """
    Read a list of players (each one represented by a 
    dictionary), and return the list.
    """
    with open(filepath) as csvfile:
        soccerplayers = csv.DictReader(csvfile)
        return list(soccerplayers)

此功能只关注一件事:阅读玩家并返回列表。一旦阅读,我们就可以将球员分配给球队:

def assign_teams(players, teams):
    """
    Given a list of players and a list of teams, randomly assign
    players to teams--but in a fair way that balances experienced 
    players as evenly as possible across teams. Returns a dictionary 
    mapping team name -> list of players on the team.
    """
    # shuffle order of teams and players so there's no hint of 
    # favoritism
    random.shuffle(teams)
    random.shuffle(players)

    # partition player list into experienced and inexperienced players
    experienced   = [ p for p in players if p['Soccer Experience'] == 'YES']
    inexperienced = [ p for p in players if p['Soccer Experience'] == 'NO']

    # create a roster
    n_teams = len(teams)
    roster = {team_name: [] for team_name in teams}

    # pick the experienced players (round-robin)
    for i, player in enumerate(experienced):
        team = teams[i % n_teams]
        roster[team].append(player)

    # add inexperienced players (round-robin)
    for i, player in enumerate(inexperienced):
        team = teams[i % n_teams]
        roster[team].append(player)

    return roster

请注意,从未提及过特定的团队。这使得例程可以扩展到任意数量的团队或玩家。它使用一个常见的索引 - 模块列表大小技巧来轮换团队名称,依次分配每个名称。

一旦在名单上分配了团队,就该把它们写到结果文件中了:

def write_roster(roster, filepath):
    """
    Write a roster dictionary to the given filepath.
    """
    fields = ["Name", "Soccer Experience", "Guardian Name(s)"]
    with open(filepath, 'w') as f:
        for team in roster.keys():
            f.write(team + '\n')
            for player in roster[team]:
                # select just the desired fields for output
                row = [player[f] for f in fields]
                # construct and write out a formatted record
                formatted_row = ', '.join(row) + '\n'
                f.write(formatted_row)
            # separate teams with a little more white space
            f.write('\n')

再次注意,代码并非特定于团队名称。它不关心他们是龙还是战斗独角兽。这些值一般是处理的。

最后,您需要一些命令和控制代码来将这些功能拼接在一起:

if __name__ == "__main__":
    players = read_players('soccer_players.csv')
    teams = ['Raptors', 'Dragons', 'Sharks']
    roster = assign_teams(players, teams)
    write_roster(roster, 'teams.txt')
    print('done!')

虽然分配是随机的(按设计),但一次运行会发出文件teams.txt,如下所示。请注意,我并不担心有18名球员。它适用于18,但它同样适用于6,9,12,......并且实际上也适用于5,19和67.(但是,如果你打算在现实生活中使用它,那么可能会看到许多奇怪的玩家名单,你可能想进一步改进这里使用的相当简单的公平算法。)

Dragons
Todd Jacobs, YES, Robert and Virginia Jacobs
Doug Jones, NO, Mary and Perry Jones
David Nork, NO, Dan and Stacy Nork

Raptors
Joe Smith, YES, Jim and Jan Smith
Will Smith, NO, Bill and Nancy Smith
Mark Jackson, NO, Jack and Frank Jackson

Sharks
Bill Smith, YES, Jim and Jan Smith
Andy Able, NO, Noah Able
Paul Pork, NO, Paul and Paulette Pork