TAGS :Viewed: 4 - Published at: a few seconds ago

[ Unpack only the first few columns from the CSV reader? ]

When reading a CSV file:

with open("foo.csv") as foo:
    for (a,b) in csv.reader(foo):
        ....

I get the error

ValueError: too many values to unpack

when the file contains more than two columns.

Is there a way to unpack the first two columns and ignore the rest?

I guess I can do

with open("foo.csv") as foo:
    for row in csv.reader(foo):
        a,b = row[0:2]
        ....

but that looks ugly.

PS. I am using python2, if that matters.

Answer 1


In python2 there doesn't seem to be any mechanism to limit number of columns returned by csv.reader. I've checked sources of cpython 27 -> csv.Reader_iternext() and the only possibility of ending row reading (I've just spent few moments analysing the code) is to encounter one of characters: \r\n\0.

You also can use DictReader:

If the row read has more fields than the fieldnames sequence, the remaining data is added as a sequence keyed by the value of restkey. If the row read has fewer fields than the fieldnames sequence, the remaining keys take the value of the optional restval parameter.

So you can do:

with open("foo.csv") as foo:
    for row in csv.DictReader(csvfile=foo, fieldnames=('a', 'b')):
        a = row['a']
        b = row['b']
        ....

But I personally would go with checking length of the row and using (a,b) = row[:2].

Answer 2


In python3 you should be able to do this:

with open("foo.csv") as foo:
    for row in csv.reader(foo):
        a,b,*unused = row

But since you use python2, if you assure that every line has at least 3 columns you can do this:

with open("foo.csv") as foo:
    for line in foo:
        a,b,*unused = line.split(',', 3)
        # splits every line by separator ','
        # but stops splitting after the first two   (maxsplit) 

Or you can just use pandas, somehow like that:

import pandas

dataframe = pandas.read_csv("foo.csv", usecols=[0,1])

Answer 3


Use a generator:

with open("foo.csv") as foo:
    for a,b in (r[0:2] for r in csv.reader(foo)):
         ...

This more clearly displays your intent. It's basically equivalent to your "ugly" way of doing it, but it's much easier to look at.