-1

I have a text file with names and results. If the name already exists, only the result should be updated. I tried with this code and many others, but without success.

The content of the text file looks like this:

Ann, 200
Buddy, 10
Mark, 180
Luis, 100

PS: I started 2 weeks ago, so don't judge my bad code.

from os import rename


def updatescore(username, score):
    file = open("mynewscores.txt", "r")
    new_file = open("mynewscores2.txt", "w")
    for line in file:
        if username in line:
            splitted = line.split(",")
            splitted[1] = score
            joined = "".join(splitted)
            new_file.write(joined)
        new_file.write(line)
    file.close()
    new_file.close()


maks = updatescore("Buddy", "200")
print(maks)
accdias
  • 5,160
  • 3
  • 19
  • 31
  • _but without success._ Can you be more specific? What's wrong with the code? You also haven't clearly explained what the program is meant to do, which means we all have to try to guess from your code. – AMC Dec 23 '19 at 19:03

6 Answers6

2

I would suggest reading the csv in as a dictionary and just update the one value.

import csv
d = {}
with open('test.txt', newline='') as f:
    reader = csv.reader(f)
    for row in reader:
            key,value = row
            d[key] = value

d['Buddy'] = 200

with open('test2.txt','w', newline='') as f:
    writer = csv.writer(f)
    for key, value in d.items():
            writer.writerow([key,value])
Chris
  • 15,819
  • 3
  • 24
  • 37
  • 1
    This is missing the csv import eh. Also instead of iterating over each pair in the dictionary, you can just call `writer.writerows(d.items())`. – AMC Dec 23 '19 at 19:04
0

So what needed to be different mostly is that when in your for loop you said to put line in the new text file, but it's never said to Not do that when wanting to replace a score, all that was needed was an else statement below the if statement:

from os import rename


def updatescore(username, score):
    file = open("mynewscores.txt", "r")
    new_file = open("mynewscores2.txt", "w")
    for line in file:
        if username in line:
            splitted = line.split(",")
            splitted[1] = score
            print (splitted)
            joined = ", ".join(splitted)
            print(joined)
            new_file.write(joined+'\n')
        else:
            new_file.write(line)



    file.close()
    new_file.close()


maks = updatescore("Buddy", "200")
print(maks)
  • Also Fixed some writing to get the wanted outcome like ", ".join and (joined+'\n') – Adam m. Chebil Dec 23 '19 at 17:42
  • No context managers for the files? What does `updatescore` return, exactly? Looking at OP's data, there is a space after the comma. You split on **just** the comma, which means there is an extra space in front of the values. This may not be an issue in this particular situation, but it could be problematic down the line. – AMC Dec 23 '19 at 19:29
  • @AMC updatescore and splitting on the comma are not my code, I just copied what OP gave, I understand what you are saying but i didn't change much other than what was needed for OP's asked outcome. If you want to know anything else about the code you should ask OP and his/her/their reasons for the code itself. – Adam m. Chebil Dec 23 '19 at 20:49
0

You can try this, add the username if it doesn't exist, else update it.

def updatescore(username, score):
    with open("mynewscores.txt", "r+") as file:
        line = file.readline()
        while line:
            if username in line:
                file.seek(file.tell() - len(line))
                file.write(f"{username}, {score}")
                return
            line = file.readline()
        file.write(f"\n{username}, {score}")

maks = updatescore("Buddy", "300")
maks = updatescore("Mario", "50")
Marsilinou Zaky
  • 1,038
  • 7
  • 17
  • I believe bare return statements are discouraged. You can just use a break instead. – AMC Dec 23 '19 at 19:05
  • Using break wouldn't be valid here since it would execute what's after the loop! Going this route would need an extra bool to check if it was added or not – Marsilinou Zaky Dec 23 '19 at 19:14
  • A break can still work, you just need an else statement after the loop. Can you explain what the `seek` is for? Why the while loop, won't a for loop do the job? – AMC Dec 23 '19 at 19:16
  • 1
    @AMC For loop won't do the job here you can refer to this post here https://stackoverflow.com/a/42150352/8692977 I use seek to basically unread a line to overwrite it with the new line. Actually i just found an issue with this solution if the old score is longer it won't overwrite the whole thing. I will fix it after work! – Marsilinou Zaky Dec 23 '19 at 19:50
0

You have new_file.write(joined) inside the if block, which is good, but you also have new_file.write(line) outside the if block.

Outside the if block, it's putting both the original and fixed lines into the file, and since you're using write() instead of writelines() both versions get put on the same line: there's no \n newline character.

You also want to add the comma: joined = ','.join(splitted) since you took the commas out when you used line.split(',')

I got the result you seem to be expecting when I put in both these fixes.

Next time you should include what you are expecting for output and what you're giving as input. It might be helpful if you also include what Error or result you actually got.

Welcome to Python BTW

Liam Duncan
  • 124
  • 1
  • 3
0

Removed issues from your code:

def updatescore(username, score):
    file = open("mynewscores.txt", "r")
    new_file = open("mynewscores2.txt", "w")
    for line in file.readlines():
        splitted = line.split(",")
        if username == splitted[0].strip():         
            splitted[1] = str(score)
            joined = ",".join(splitted)
            new_file.write(joined)
        else:
            new_file.write(line)

    file.close()
    new_file.close()
Ashwani
  • 1,340
  • 1
  • 16
  • 34
  • No context managers? Why use `.readlines()` instead of iterating over the file object directly? It looks like you should use the `csv` module. rather than splitting and joining and all that manually. – AMC Dec 23 '19 at 19:28
  • My point is that I think you haven't caught **all** the issues. – AMC Dec 24 '19 at 15:35
0

I believe this is the simplest/most straightforward way of doing things.

Code:

import csv


def update_score(name: str, score: int) -> None:
    with open('../resources/name_data.csv', newline='') as file_obj:
        reader = csv.reader(file_obj)
        data_dict = dict(curr_row for curr_row in reader)

    data_dict[name] = score

    with open('../out/name_data_out.csv', 'w', newline='') as file_obj:
        writer = csv.writer(file_obj)
        writer.writerows(data_dict.items())


update_score('Buddy', 200)

Input file:

Ann,200
Buddy,10
Mark,180
Luis,100

Output file:

Ann,200
Buddy,200
Mark,180
Luis,100
AMC
  • 2,642
  • 7
  • 13
  • 35