有没有更好的,pythonic方式来做到这一点?

Sch*_*tti 10 python dictionary set

这是我的第一个python程序 -

要求:在每行中读取由{adId UserId}组成的文件.对于每个ad​​Id,打印唯一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))
Run Code Online (Sandbox Code Playgroud)

谢谢.

unu*_*tbu 18

恭喜,您的代码非常好.您可以使用一些小技巧来缩短/简化它.

有一个名为defaultdict的漂亮对象类型,由collections模块提供.您无需检查adDict是否具有adId键,而是可以设置一个默认的dict,其作用类似于常规字典,除非它在没有键时自动为您提供空集().所以你可以改变

if ( adId in adDict ):
    adDict[adId].add(userId)
else:
    adDict[adId] = set(userId)
Run Code Online (Sandbox Code Playgroud)

简单地说

adDict[adId].add(userId)
Run Code Online (Sandbox Code Playgroud)

而且,而不是

for row in reader:
    adId = row[0]
    userId = row[1]
Run Code Online (Sandbox Code Playgroud)

你可以缩短它

for adId,userId in reader:
Run Code Online (Sandbox Code Playgroud)

编辑:正如帕克在评论中指出的那样,

for key, value in adDict.iteritems():
Run Code Online (Sandbox Code Playgroud)

如果要在循环中同时使用键和值,则迭代dict是最有效的方法.在Python3中,您可以使用

for key, value in adDict.items():
Run Code Online (Sandbox Code Playgroud)

因为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))
Run Code Online (Sandbox Code Playgroud)


Ale*_*lli 10

代码行:

adDict[adId] = set(userId)
Run Code Online (Sandbox Code Playgroud)

不可能做你想要什么-它将把字符串userId为字母顺序,因此,例如,如果userIdaleax你会得到一组四个选项,就像,比如说,set(['a', 'l', 'e', 'x']).稍后,.add(userId)when userIdaleax再次添加第五个项,即字符串'aleax',因为.add(与set initializer不同,它采用iterable作为其参数)将单个项作为其参数.

要使用单个项目创建集合,请set([userId])改为使用.

这是一个相当频繁的bug,所以我想清楚地解释它.话虽如此,defaultdict正如其他答案中所建议的那样,显然是正确的方法(避免setdefault,这从来就不是一个好的设计,既没有良好的表现,也不是很模糊).

我也会避免csv在每一行上使用.split和.strip的简单循环有点过分了...


sth*_*sth 7

您可以将for循环缩短为:

for row in reader:
  adDict.setdefault(row[0], set()).add(row[1])
Run Code Online (Sandbox Code Playgroud)