Dictionary 有没有更好的,像蟒蛇一样的方法?

Dictionary 有没有更好的,像蟒蛇一样的方法?,dictionary,set,python,Dictionary,Set,Python,这是我的第一个python程序- 要求:读取每行中由{adId UserId}组成的文件。对于每个adId,打印唯一用户ID的数量 这是我的代码,是从阅读python文档中整理出来的。你能不能给我一些反馈,告诉我如何用更像python的方式写这篇文章 代码: import csv adDict = {} reader = csv.reader(open("some.csv"), delimiter=' ') for row in reader: adId = row[0] us

这是我的第一个python程序-

要求:读取每行中由{adId UserId}组成的文件。对于每个adId,打印唯一用户ID的数量

这是我的代码,是从阅读python文档中整理出来的。你能不能给我一些反馈,告诉我如何用更像python的方式写这篇文章

代码:

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))

谢谢。

您可以将for循环缩短为:

for row in reader:
  adDict.setdefault(row[0], set()).add(row[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)))

恭喜你,你的代码很好。 有一些小技巧可以让它变得更短/更简单

集合模块提供了一个名为defaultdict的漂亮对象类型。不必检查adDict是否有adId密钥,您可以设置一个defaultdict,其作用类似于常规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))

只是一些零碎的东西:

要将行列表提取到变量中,请执行以下操作:

adId, userId = row
if语句不需要大括号:

if adId in adDict:
您可以使用异常来处理dict中缺少的密钥,但这两种方法都很有效,例如:

try:
    adDict[adId].add(userId)
except KeyError:
    adDict[adId] = set(userId)
而不是:

for row in reader:
    adId = row[0]
    userId = row[1]
if ( adId in adDict ):
    adDict[adId].add(userId)
else:
    adDict[adId] = set(userId)
使用自动顺序解包:

for (adId, userId) in reader:
在:

你不需要括号

而不是:

for row in reader:
    adId = row[0]
    userId = row[1]
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()

打印时:

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)))

由于您只有一个以空格分隔的文件,我将执行以下操作:

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]))
代码行:

adDict[adId] = set(userId)
不太可能做你想做的事情——它将字符串
userId
视为一个字母序列,因此,例如,如果
userId
was
aleax
,你会得到一个包含四个项目的集合,就像,
set(['a','l','e','x'])
。稍后,
.add(userId)
userId
aleax
时,将再次添加第五项,字符串
'aleax'
,因为
.add
(与设置初始值设定项不同,设置初始值设定项将iterable作为其参数)将单个项作为其参数

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

这是一个相当频繁的错误,所以我想解释清楚。也就是说,其他答案中建议的
defaultdict
显然是正确的方法(避免
setdefault
,这从来都不是一个好的设计,性能也不好,而且非常模糊)


我还想避免对csv的过度使用,而选择一个简单的循环,在每一行上使用.split和.strip…

这里有一些很好的答案

我特别喜欢的一个技巧是使我的代码在将来更易于重用

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的编程访问

+1-不错!我要是早点知道setDefault方法就好了!酷-所以setdefault(行[0],set())返回一个set实例,然后我们在其上添加一个。是的,尽管可能缺点是基于异常的逻辑更难理解。谢谢John!在过去的5年里,我从事C语言编码行业,所以没有教授啊,对不起;这类问题通常被分配给初学的学生作为家庭作业。酷-我将阅读更多有趣的技巧集。还有,为什么我们要说“导入csv”,而必须说“从集合导入defaultdict”?@Schitti-使用from是一种快捷方式。这意味着您可以键入defaultdict而不是collections.defaultdict。它是完全可选的,不过通过将符号defaultdict导入模块的名称空间会产生一些高级程序员可能喜欢的其他有用效果。@Schitti-任何一种形式都可以。如果您只想使用
import
语句,可以说
import collections.defaultdict
——但是,每次使用它时,都必须将其称为
collections.defaultdict
。相反,正如您在~unutbu的答案中所看到的,您现在只需将其称为
defaultdict
。您还可以在导入模块时更改其名称;例如,
import collections.defaultdict as defDi
from collections import defaultdict as defDi
-然后您可以使用
defDi
而不是
defaultdict
作为键,d中的值。items()比
作为键输入d:value=d[key]
的更好的做法。第一个版本只访问每个元素一次。第二个版本访问每个元素一次以获得键列表,然后必须在dict中查找每个键。它是O(n)对O(n*logn)。我认为在这种特殊情况下,可读性论证可能会出现任何一种情况,但性能差异非常显著(特别是对于大型dict而言),因此第一个版本肯定是赢家。@Parker,谢谢你有趣的评论!你说服了我,但我试着写一些演示代码。令我惊讶的是,
key in d
似乎比
key,value in d.items()更快。这是我测试的代码:
python-mtimeit-s“导入测试”测试。key_in_d()“
每个循环花费409毫秒,
python-mtimeit-s“导入测试”测试。key_in_d_items()”
每个循环花费631毫秒。你觉得怎么样?谢谢。我想这可以避免创建一个新的reader类。因为我的名声不到15岁,所以我不能投票给你。我喜欢这个。我只是想推荐使用
defaultdict(set)
。但是,此代码分解每个l