需要更有效的方法来解析Python中的csv文件

时间:2011-06-29 02:23:17

标签: python csv

这是一个示例csv文件

id, serial_no
2, 500
2, 501
2, 502
3, 600
3, 601

这是我正在寻找的输出(带有id列表的serial_no列表):

[2, [500,501,502]]
[3, [600, 601]]

我已经实现了我的解决方案,但代码太多了,我确信有更好的解决方案。还在学习Python,我还不知道所有的技巧。

file = 'test.csv'

data = csv.reader(open(file))
fields = data.next()

for row in data:
  each_row = []     
    each_row.append(row[0])
    each_row.append(row[1])
    zipped_data.append(each_row)
for rec in zipped_data:
  if rec[0] not in ids:
    ids.append(rec[0])
for id in ids:
    for rec in zipped_data:
      if rec[0] == id:
        ser_no.append(rec[1])
  tmp.append(id)
  tmp.append(ser_no)
  print tmp
  tmp = []
  ser_no = []

**为了简化代码,我省略了var初始化

print tmp

给我上面提到的输出。我知道有更好的方法来做这个或pythonic方式来做到这一点。太乱了!任何建议都会很棒!

5 个答案:

答案 0 :(得分:12)

from collections import defaultdict

records = defaultdict(list)

file = 'test.csv'

data = csv.reader(open(file))
fields = data.next()

for row in data:
    records[row[0]].append(row[1])

#sorting by ids since keys don't maintain order
results = sorted(records.items(), key=lambda x: x[0])
print results

如果serial_nos列表必须是唯一的,只需将defaultdict(list)替换为defaultdict(set),将records[row[0]].append(row[1])替换为records[row[0]].add(row[1])

答案 1 :(得分:5)

而不是列表,我会将其设为collections.defaultdict(list),然后只需在值上调用append()方法。

result = collections.defaultdict(list)
for row in data:
  result[row[0]].append(row[1])

答案 2 :(得分:2)

这是我写的一个版本,看起来已经有很多答案了。

您可能喜欢使用csv.DictReader,通过字段名称(从标题/第一行)轻松访问每列。

#!/usr/bin/python
import csv

myFile = open('sample.csv','rb')
csvFile = csv.DictReader(myFile)
# first row will be used for field names (by default)

myData = {}

for myRow in csvFile:
    myId = myRow['id']
    if not myData.has_key(myId): myData[myId] = []
    myData[myId].append(myRow['serial_no'])

for myId in sorted(myData):
    print '%s %s' % (myId, myData[myId])

myFile.close()

答案 3 :(得分:1)

一些观察结果:

0)file是内置的(open的同义词),因此它是变量名称的不良选择。此外,变量实际上包含文件名称,因此......

1)文件一读完就可以关闭。最简单的方法是使用with块。

2)第一个循环似乎遍历所有行,从每个行中获取前两个元素,并列出包含这些结果的列表。但是,您的行已经只包含两个元素,因此没有净效果。 CSV读取器已经是行上的迭代器,从迭代器创建列表的简单方法是将它传递给列表构造函数。

3)您可以通过手动检查来制作唯一ID值列表。唯一事物列表更好地称为set,而Python set会自动确保唯一性。

4)您的数据名称为zipped_data。这是有道理的:将zip应用于行列表会产生列列表 - 而ID只是第一列,转换为集合。

5)我们可以使用列表推导来构建给定ID的序列号列表。不要告诉Python如何制作列表;告诉它你想要的东西。

6)在我们得到结果时打印结果有点混乱和不灵活;更好地创建整个数据块(然后我们有代码创建数据,所以我们可以用它来做其他事情,而不仅仅是打印它而忘记它)。

应用这些想法,我们得到:

filename = 'test.csv'

with open(filename) as in_file:
    data = csv.reader(in_file)
    data.next() # ignore the field labels
    rows = list(data) # read the rest of the rows from the iterator

print [
    # We want a list of all serial numbers from rows with a matching ID...
    [serial_no for row_id, serial_no in rows if row_id == id]
    # for each of the IDs that there is to match, which come from making
    # a set from the first column of the data.
    for id in set(zip(*rows)[0])
]

使用groupby模块中的itertools函数,我们可能做得更好。

答案 4 :(得分:0)

使用itertools.groupby的示例。 仅当行已按ID

分组时才有效
from csv import DictReader
from itertools import groupby
from operator import itemgetter

filename = 'test.csv'

# the context manager ensures that infile is closed when it goes out of scope
with open(filename) as infile:

    # group by id - this requires that the rows are already grouped by id
    groups = groupby(DictReader(infile), key=itemgetter('id'))

    # loop through the groups printing a list for each one
    for i,j in groups:
        print [i, map(itemgetter(' serial_no'), list(j))]

注意' serial_no'前面的空格。这是因为输入文件中逗号之后的空格