core_light
core_light

Reputation: 85

Writing specific value back to .csv, Python

I have a .csv file with some data that i would like to change. It looks like this:

item_name,item_cost,item_priority,item_required,item_completed
item 1,11.21,2,r
item 2,411.21,3,r
item 3,40.0,1,r,c

My code runs most of what i need but i am unsure of how to write back on my .csv to produce this result

item_name,item_cost,item_priority,item_required,item_completed
item 1,11.21,2,x
item 2,411.21,3,r
item 3,40.0,1,r,c

My code:

print("Enter the item number:")
    line_count = 0
    marked_item = int(input())
    with open("items.csv", 'r') as f:
        reader = csv.DictReader(f, delimiter=',')
        for line in reader:
            if line["item_required"] == 'r':
                line_count += 1
                if marked_item == line_count:
                    new_list = line
                    print(new_list)
                    for key, value in new_list.items():
                        if value == "r":
                            new_list['item_required'] = "x"
                            print(new_list)
    with open("items.csv", 'a') as f:
        writer = csv.writer(f)
        writer.writerow(new_list.values())

Upvotes: 3

Views: 123

Answers (3)

Scarabee
Scarabee

Reputation: 5704

Using pandas:

import pandas as pd

df = pd.read_csv("items.csv")

print("Enter the item number:")
marked_item = int(input())

df.set_value(marked_item - 1, 'item_required', 'x')

# This is the extra feature you required:
df.set_value(marked_item - 1, 'item_completed', 'c')

df.to_csv("items.csv", index = False)

Result when marked_item = 1:

item_name,item_cost,item_priority,item_required,item_completed
item 1,11.21,2,x,c
item 2,411.21,3,r,
item 3,40.0,1,r,c

Note that according to RFC4180 you should keep the trailing commas.

Upvotes: 1

Neeraj Komuravalli
Neeraj Komuravalli

Reputation: 306

I guess this should do the trick:

  1. Open a file which can read and written to update it (use "+r" for that)
  2. instead of opening it again write it right there using csvfilewriter, which we create at the start.

file.py

import csv
fieldnames = ["item_name","item_cost","item_priority","item_required","item_completed"]

csvfile = open("items.csv", 'r+')
csvfilewriter = csv.DictWriter(csvfile, fieldnames=fieldnames,dialect='excel', delimiter=',')
csvfilewriter.writeheader()

print("Enter the item number:") 
line_count = 0
marked_item = int(input())
with open("items.csv", 'r') as f:
    reader = csv.DictReader(f, delimiter=',')
    for line in reader:
        if line["item_required"] == 'r':
            line_count += 1
            if marked_item == line_count:
                new_list = line
                print(new_list)
                for key, value in new_list.items():
                    if value == "r":
                        new_list['item_required'] = "x"
                        print(new_list)
                        csvfilewriter.writerow(new_list)

If you don't want to update the csv but want to write a new one, below is the code:

import csv

fieldnames = ["item_name","item_cost","item_priority","item_required","item_completed"]

csvfile = open("items_new.csv", 'w')
csvfilewriter = csv.DictWriter(csvfile, fieldnames=fieldnames,dialect='excel', delimiter=',')
csvfilewriter.writeheader()

print("Enter the item number:")
line_count = 0
marked_item = int(input())
with open("items.csv", 'r') as f:
    reader = csv.DictReader(f, delimiter=',')
    for line in reader:
        if line["item_required"] == 'r':
            line_count += 1
            if marked_item == line_count:
                new_list = line
                print(new_list)
                for key, value in new_list.items():
                    if value == "r":
                        new_list['item_required'] = "x"
                        print(new_list)
                        csvfilewriter.writerow(new_list)

            else:
                csvfilewriter.writerow(line)

Upvotes: 0

Jean-François Fabre
Jean-François Fabre

Reputation: 140186

There are several problems here

  • you're using a DictReader, which is good to read data, but not as good to read and write data as the original file, since dictionaries do not ensure column order (unless you don't care, but most of the time people don't want columns to be swapped). I just read the title, find the index of the column title, and use this index in the rest of the code (no dicts = faster)
  • when you write you append to the csv. You have to delete old contents, not append. And use newline='' or you get a lot of blank lines (python 3) or "wb" (python 2)
  • when you read, you need to store all values, not only the one you want to change, or you won't be able to write back all the data (since you're replacing the original file)
  • when you modify, you do overcomplex stuff I just replaced by a simple replace in list at the given index (after all you want to change r to x at a given row)

Here's the fixed code taking all aforementioned remarks into account

EDIT: added the feature you request after: add a c after x if not already there, extending the row if needed

import csv

line_count = 0
marked_item = int(input())
with open("items.csv", 'r') as f:
    reader = csv.reader(f, delimiter=',')
    title = next(reader)  # title
    idx = title.index("item_required")  # index of the column we target

    lines=[]
    for line in reader:
        if line[idx] == 'r':
            line_count += 1
            if marked_item == line_count:
                line[idx] = 'x'
                # add 'c' after x (or replace if column exists)
                if len(line)>idx+1:  # check len
                   line[idx+1] = 'c'
                else:
                   line.append('c')
        lines.append(line)

with open("items.csv", 'w',newline='') as f:
    writer = csv.writer(f,delimiter=',')
    writer.writerow(title)
    writer.writerows(lines)

Upvotes: 1

Related Questions