1

Goal is to replace the second field of csv_line with new_item in an elegant way. This question is different from the topics listed by Rawing because here we are working with a different data structure, though we can use other topics to get inspired.

# Please assume that csv_line has not been imported from a file.
csv_line = 'unknown_item1,unknown_old_item2,unknown_item3'
new_item = 'unknown_new_item2'
goal = 'unknown_item1,unknown_new_item2,unknown_item3'

# Works but error prone. Non-replaced items could be inadvertently swapped.
# In addition, not convenient if string has many fields.
item1, item2, item3 = csv_line.split(',')
result = ','.join([item1, new_item, item3])
print(result)  # unknown_item1,unknown_new_item2,unknown_item3

# Less error prone but ugly.
result_list = []
new_item_idx = 1
for i, item in enumerate(csv_line.split(',')):
    result_list += [item] if i != new_item_idx else [new_item]
result = ','.join(result_list)
print(result)  # unknown_item1,unknown_new_item2,unknown_item3

# Ideal (not-error prone) but not working.
csv_line.split(',')[1] = new_item
print(csv_line)  # unknown_item1,unknown_old_item2,unknown_item3
MLguy
  • 1,776
  • 3
  • 15
  • 28
  • 2
    Possible duplicate of [Change specific value in CSV file via Python](https://stackoverflow.com/questions/11033590/change-specific-value-in-csv-file-via-python) – Aran-Fey Jan 31 '18 at 11:15
  • 1
    Alternative dupe: https://stackoverflow.com/questions/8905165/replace-data-in-csv-file-using-python – Aran-Fey Jan 31 '18 at 11:15
  • Possible duplicate of [Replace data in csv file using python](https://stackoverflow.com/questions/8905165/replace-data-in-csv-file-using-python) – Andras Deak -- Слава Україні Jan 31 '18 at 11:35
  • Wrong IMO. Here we are using a different data structure (string) and no IO. – MLguy Jan 31 '18 at 11:37
  • @MLguy Where does that string come from, then? – Aran-Fey Jan 31 '18 at 11:40
  • @Rawing The solution must not depend on from where the string comes from. – MLguy Jan 31 '18 at 11:53
  • 1
    @MLguy It doesn't depend on anything. You can wrap the string in a `StringIO` and use a csv reader on that. That's the correct way to handle csv data. But if you can, you should avoid reading the data as a string in the first place. – Aran-Fey Jan 31 '18 at 12:04
  • @Rawing `.split(',')` answers the question elegantly and is 8x times faster. – MLguy Jan 31 '18 at 12:36
  • @MLguy I've posted this on pretty much every single answer down there, but I'll say it one last time: ___Splitting csv data on commas is incorrect.___ – Aran-Fey Jan 31 '18 at 12:38

4 Answers4

3

The second item could be replaced using Python's CSV library by making use of io.StringIO() objects. This behave like files but can be read as a string:

import csv
import io

csv_line = 'unknown_item1,unknown_old_item2,unknown_item3'
new_item = 'unknown_new_item2'

row = next(csv.reader(io.StringIO(csv_line)))
row[1] = new_item
output = io.StringIO()
csv.writer(output).writerow(row)
goal = output.getvalue()

print(goal)

This would display goal as:

unknown_item1,unknown_new_item2,unknown_item3
Martin Evans
  • 45,791
  • 17
  • 81
  • 97
  • What could be the rationale for accepting this answer considering that it involves more logic than using `split(',')`? – MLguy Jan 31 '18 at 11:45
  • 1
    As it is capable of correctly processing full CSV entries such as `abc,"hello, world",def` – Martin Evans Jan 31 '18 at 11:46
2
l = csv_line.split(',')
l[1] = new_item
csv_line = ','.join(l)
talz
  • 1,004
  • 9
  • 22
  • 1
    You should use the csv module instead of splitting on commas. – Aran-Fey Jan 31 '18 at 11:18
  • 2
    @Rawing, `csv` module is for "CSV File Reading and Writing". The question is about a "string formatted as csv line". The asker could have just used this to mean "comma delimited one line string". We don't even know if there are any files involved... – talz Jan 31 '18 at 11:29
  • csv data is more than just text separated by commas, so if you just split on commas, your program is incorrect. Unless the input string materialized out of nowhere, it's almost certainly being read from a file (or other file-like object) that can be wrapped in a csv reader. And if it isn't, you can wrap the string in a `StringIO` object. A small price to pay in exchange for a program that works correctly. – Aran-Fey Jan 31 '18 at 12:08
1

In the line csv_line.split(',')[1] = new_item, you do not alter the csv_line variable at all. You need to assign the new list created with .split() to a variable before you can change the elements within it:

new_csv = csv_line.split(',')
new_csv[1] = new_item

print(','.join(new_csv))
Tynan J
  • 69
  • 6
  • 1
    You should use the csv module instead of splitting on commas. – Aran-Fey Jan 31 '18 at 11:18
  • 3
    Your right, but csv_line is given as a string, so it would be pointless to involve the csv libary in this case. – Tynan J Jan 31 '18 at 11:22
  • 1
    It's never pointless to include a library that makes your code work correctly. Besides, we don't know where the OP is getting their data from. If the input is read from any file-like object, wrapping it in a csv reader is trivial. – Aran-Fey Jan 31 '18 at 11:27
  • @Tynan I've accepted talz's answer since he's been a few seconds faster and answers are the same. – MLguy Jan 31 '18 at 11:59
-1

This seems the most pythonic:

csv_line = 'unknown_item1,old_item2,unknown_item3'
old_index = 1
new_item = 'new_item2'
goal = 'unknown_item1,new_item2,unknown_item3'

items = csv_line.split(',')
items[old_index] = new_item

print(','.join(items))
print(goal)

Output:

unknown_item1,new_item2,unknown_item3
unknown_item1,new_item2,unknown_item3
quamrana
  • 37,849
  • 12
  • 53
  • 71
  • 1
    You should use the csv module instead of splitting on commas. – Aran-Fey Jan 31 '18 at 11:18
  • @Rawing I am unclear how the `csv` module splits a comma delimited string – quamrana Jan 31 '18 at 11:20
  • The starting assumption is that `old_item2` is unknown, so we can't use `!=`. – MLguy Jan 31 '18 at 11:24
  • Ok, I'll update my answer with code which replaces the second field. – quamrana Jan 31 '18 at 11:26
  • 1
    The idea is to use a csv reader to read the input so that it is no longer a string. We don't know where OP is getting this string from, but chances are it's being read from a file or file-like object. Wrapping that in a csv reader is trivial. – Aran-Fey Jan 31 '18 at 11:29
  • Data structure is a plain string and no .csv file is involved here. – MLguy Jan 31 '18 at 11:38