Justus Niemzok
Justus Niemzok

Reputation: 63

How to handle lists as single values in csv with Python

I am handling a csv import and got troubles with a value that should be in list form but is read as string.

One of the csv rows looks like the following:

    ['name1', "['name2', 'name3']"]

As you can see the value in the second column is a list but is read as a string. My problem is that I need to iterate through that list and the length of that list can vary from row to row.

I am wondering where the problem lies. Can csv read not handle a list? Is there a way to turn that string in the second column into a list rather than using regex? Here is the code that I am running:

    import csv
    import os

    content = []
    file_path = os.path.abspath(file)
    if os.path.exists(file_path):
      with open(file_path, 'rb') as csvfile:
        csvreader = csv.reader(csvfile, delimiter = ',')
      for row in csvreader:
        content.append(row)
      for row in content[1:5]:
        print row
      print row[0], row[1]
      for name in row[1]:
        print name

The output row looks as above but when iterating though row[1] it does not iterate though the list of names but through every single character. Anyone got an idea? Thanks in advance for any help!

Upvotes: 0

Views: 112

Answers (4)

Anand S Kumar
Anand S Kumar

Reputation: 90899

An easy way to convert string to list is using ast.literal_eval function.

Example -

>>> import ast
>>> s = "['name2', 'name3']"
>>> s
"['name2', 'name3']"
>>> l = ast.literal_eval(s)
>>> l
['name2', 'name3']
>>> type(l)
<class 'list'>

From ast documentation -

ast.literal_eval(node_or_string)

Safely evaluate an expression node or a Unicode or Latin-1 encoded string containing a Python literal or container display. The string or node provided may only consist of the following Python literal structures: strings, numbers, tuples, lists, dicts, booleans, and None.

But if your complete csv looks like that, you should consider using json to parse the csv, rather than csv module.

Upvotes: 3

vks
vks

Reputation: 67968

x=['name1', "['name2', 'name3']"]
import re
print [ast.literal_eval(i) if re.match(r"\[.*?\]",i) else i for i in x ]

OUTPUT: ['name1', ['name2', 'name3']]

You can use ast.literal_eval and re to convert string in list to list and leave others as they are.

Upvotes: 0

itzMEonTV
itzMEonTV

Reputation: 20349

Try this, using literal_eval to convert string to corresponding class

from ast import literal_eval
for name in literal_eval(row[1]):
   print name

or

for name in eval(row[1]):
   print name

Upvotes: 1

Abhijit
Abhijit

Reputation: 63737

Considering your second list item is a valid python data type, you can use ast.literal_eval to parse the string

>>> import ast
>>> ast.literal_eval("['name2', 'name3']")
['name2', 'name3']

So in your particular case,you may want to do the following

  .............
  row[1] = ast.literal_eval(row[1])
  print row[0], row[1]
  for name in row[1]:
    print name    

Upvotes: 1

Related Questions