0

I have a csv file containing rows of data about different basketball players, I know that to read a row/column I have been using the following code:

with open(playerDocument) as csvfile:
     reader = csv.DictReader(csvfile)
     for row in reader:
          if row["Name"] == "Jerrold":
               print(row["Name"])

How would I add 2 to a specific cell in the csv file?

H_Lev1
  • 253
  • 4
  • 18

1 Answers1

1

Normally that is not done. Because it is not as CSV files are meant to work.

CSV files are loose text files, which can contain variable length free information for each field, provided the number of fields in all lines are the same. But, although they can be specified so, the field lengths themselves are not fixed. In this case, for example, when the score would change from "8" to "10", you would overwrite the next field separator (","), and break the file, if you where using strictly what you want.

Actually, any text file in computing is usually meant as a "source" of information only - and whenever the information change, the usual thing to do is just to re-write the whole file again (and delete the previous version).

That may seem like a waste of resources - but at the Operating System/Hardware level, the minimum ammount of bytes written to disk is usually 4096 at once. It means that even if you manage creating your program to change a single character on disk, recording it will still write back 4000+ bytes to disk.

In a case like this, the most recomended approach are: (1) Recreate the whole file for each change you have - that won't be a problem for up to a few hundred basketball players.

(2) If you have more than a few hundred (or a lot more information than a single score for each player), the best approach is to have an SQL database - and let the database controller take care of addressing the correct cell and most efficiently updating it on disk. Actually, the database approach might be good even with few records. In Python, you can have an sqlite - single file, self contained database - with no configuration and not software install.

(3) It is possible to have a CSV file that reserves, say, 5 digits minimum for each cell, and them using complicated techniques to update just those cell. It won't save computer resources (see above), and will make the maintenance of your program complicated. But it could be great to learn more about programming and how files work - as an exercise.

So - here is how a minimal program using approach (1) would look like:

import csv
import os

player_file = "players.csv"
fieldnames = None
def get_data(playerDocument):
    """
    Reads in the whole CSV file as a single dictionary, having the player name as key.
    """
    global fieldnames
    with open(playerDocument) as inputfile:
        reader = csv.DictReader(inputfile)
        fieldnames = reader.fieldnames
        return  {record["Name"]:record  for record in reader}


def update_record(data, player_name, amount=2):
    data[player_name]["Score"] += amount


def save_data(playerDocument, data):
    temp_name = playerDocument + ".temp"
    with open(temp_name, "wt") as outputfile:
        writer = csv.DictWriter(outputfile)
        writer.writeheader(fieldnames)
        writer.writerows(sorted(data.values(), key=lambda record: record["Name"]))
    os.unlink(playerDocument)
    os.rename(temp_name, playerDocument)

def main():
    player = input("Player name to update: ")
    data = get_data(player_file)
    upate_record(data, player)
    save_data(player_file)

main()
jsbueno
  • 99,910
  • 10
  • 151
  • 209
  • (I assume you are using Python 3.x - if you are on Python 2.7, the correct is "raw_input", instead of "input". – jsbueno Dec 02 '16 at 09:59
  • I'm not sure what you mean with "CSV files are loose text files, which can contain variable length free information for each field, provided the number of fields in all lines are the same." and reserving space for characters. `writer.writerows([['a', 'b', c'], ['d', 'e']])` is perfectly valid and gives the intended output. Equally, since the delimiter is specified, why does the number of characters matter since you're simply pushing the delimiter further along (in reference to you reserving 5 character spaces)? – roganjosh Dec 02 '16 at 10:08
  • You can write files with varying fields in each row, just that using them back as structured information would be unpractical. And if one is using DictReader as in this case, reading it back would fail. As for your second point - if you push the delimtier further along you would overwrite other parts of the file. You may not reqrite all the file, but you'd have to rewrite all the fiel from that point on. Otherwise. please just write code that can update a cell in CSV in place, without breaking it, and I will upvote you. Even though such code is not actually useful IRL, as explained. – jsbueno Dec 02 '16 at 11:10
  • I wasn't in any way implying that this would be a practical solution above what you have suggested :) The statement as-in in what is otherwise a very comprehensive answer could be misleading though... there is no absolute requirement for each row to contain the same number of fields. – roganjosh Dec 02 '16 at 11:14
  • I have many columns of data for each row, how would I rewrite this all at once? – H_Lev1 Dec 03 '16 at 11:41
  • ut seriously, you should consider using SQLITE instead. – jsbueno Dec 03 '16 at 17:50