这是我的第一个python程序 -
要求:在每行中读取由{adId UserId}组成的文件。对于每个adId,打印唯一userIds的数量。
这是我的代码,通过阅读python文档放在一起。你能给我一些关于如何用更多python-ish方式写这个的反馈吗?
代码:
import csv
adDict = {}
reader = csv.reader(open("some.csv"), delimiter=' ')
for row in reader:
adId = row[0]
userId = row[1]
if ( adId in adDict ):
adDict[adId].add(userId)
else:
adDict[adId] = set(userId)
for key, value in adDict.items():
print (key, ',' , len(value))
感谢。
答案 0 :(得分:18)
恭喜,您的代码非常好。 你可以使用一些小技巧来缩短它们的速度。
有一个名为defaultdict的漂亮对象类型,由collections模块提供。您无需检查adDict是否具有adId键,而是可以设置一个默认的dict,其作用类似于常规字典,除非它在没有键时自动为您提供空集()。所以你可以改变
if ( adId in adDict ):
adDict[adId].add(userId)
else:
adDict[adId] = set(userId)
简单地
adDict[adId].add(userId)
此外,而不是
for row in reader:
adId = row[0]
userId = row[1]
你可以将其缩短为
for adId,userId in reader:
编辑:正如帕克在评论中指出的那样,
for key, value in adDict.iteritems():
如果要同时使用两者,是迭代dict的最有效方法 循环中的关键和值。在Python3中,您可以使用
for key, value in adDict.items():
因为items()返回一个迭代器。
#!/usr/bin/env python
import csv
from collections import defaultdict
adDict = defaultdict(set)
reader = csv.reader(open("some.csv"), delimiter=' ')
for adId,userId in reader:
adDict[adId].add(userId)
for key,value in adDict.iteritems():
print (key, ',' , len(value))
答案 1 :(得分:10)
代码行:
adDict[adId] = set(userId)
不太可能按照您的意愿行事 - 它会将字符串userId
视为一系列字母,例如,如果userId
为aleax
,您将获得四个字符集项目,就像说set(['a', 'l', 'e', 'x'])
一样。稍后,当.add(userId)
userId
aleax
再次'aleax'
时,会添加第五项,即字符.add
,因为set([userId])
(与设置初始化程序不同,一个可迭代的参数)将一个项目作为其参数。
要制作包含单个项目的集合,请改用defaultdict
。
这是一个相当频繁的错误,所以我想清楚地解释一下。话虽如此,setdefault
正如其他答案中所建议的那样,显然是正确的方法(避免csv
,这从来就不是一个好的设计,也没有良好的表现,也不是很模糊)。
我也会避免{{1}}的有点过分支持在每一行上使用.split和.strip的简单循环......
答案 2 :(得分:7)
您可以将for循环缩短为:
for row in reader:
adDict.setdefault(row[0], set()).add(row[1])
答案 3 :(得分:3)
而不是:
for row in reader:
adId = row[0]
userId = row[1]
使用自动序列解包:
for (adId, userId) in reader:
在:
if ( adId in adDict ):
您不需要括号。
而不是:
if ( adId in adDict ):
adDict[adId].add(userId)
else:
adDict[adId] = set(userId)
使用defaultdict
:
from collections import defaultdict
adDict = defaultDict(set)
# ...
adDict[adId].add(userId)
或者,如果您的教授不允许您使用其他模块,请使用setdefault()
:
adDict.setdefault(adId, set()).add(userId)
打印时:
for key, value in adDict.items():
print (key, ',' , len(value))
使用字符串格式可能更容易格式化:
print "%s,%s" % (key, len(value))
或者,如果您使用的是Python 3:
print ("{0},{1}".format (key, len(value)))
答案 4 :(得分:3)
由于你只有一个以空格分隔的文件,我会这样做:
from __future__ import with_statement
from collections import defaultdict
ads = defaultdict(set)
with open("some.csv") as f:
for ad, user in (line.split(" ") for line in f):
ads[ad].add(user)
for ad in ads:
print "%s, %s" % (ad, len(ads[ad]))
答案 5 :(得分:3)
这里有一些很好的答案。
我特别喜欢的一个技巧是让我的代码在将来更容易重用
import csv
def parse_my_file(file_name):
# some existing code goes here
return aDict
if __name__ == "__main__":
#this gets executed if this .py file is run directly, rather than imported
aDict = parse_my_file("some.csv")
for key, value in adDict.items():
print (key, ',' , len(value))
现在,您可以从其他模块导入csv解析器,并获得对aDict的编程访问。
答案 6 :(得分:1)
我所做的唯一改变是一次从阅读器中提取多个元素,并使用字符串格式化打印语句。
import csv
adDict = {}
reader = csv.reader(open("some.csv"), delimiter=' ')
# Can extract multiple elements from a list in the iteration statement:
for adId, userId in reader:
if ( adId in adDict ):
adDict[adId].add(userId)
else:
adDict[adId] = set(userId)
for key, value in adDict.items():
# I believe this gives you more control over how things are formatted:
print ("%s, %d" % (key, len(value)))
答案 7 :(得分:1)
只是几点点:
用于将行列表提取为变量:
adId, userId = row
if语句不需要大括号:
if adId in adDict:
你可以使用异常来处理dict中缺少的Key,但两种方式都运行良好,例如:
try:
adDict[adId].add(userId)
except KeyError:
adDict[adId] = set(userId)