这是一个示例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方式来做到这一点。太乱了!任何建议都会很棒!
答案 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'
前面的空格。这是因为输入文件中逗号之后的空格