假设我有一大堆单词。举个例子:
>>> with open('/usr/share/dict/words') as f:
... words=[word for word in f.read().split('\n') if word]
如果我想通过这个单词列表的第一个字母来构建索引,这很容易:
d={}
for word in words:
if word[0].lower() in 'aeiou':
d.setdefault(word[0].lower(),[]).append(word)
# You could use defaultdict here too...
结果如下:
{'a':[list of 'a' words], 'e':[list of 'e' words], 'i': etc...}
有没有办法用Python 2.7,3 + dict理解呢?换句话说,当dict正在构建时,是否可以使用dict理解语法附加由键表示的列表?
即:
index={k[0].lower():XXX for k in words if k[0].lower() in 'aeiou'}
XXX正在创建index
时,为密钥执行追加操作或列表创建。
修改
采纳建议和基准:
def f1():
d={}
for word in words:
c=word[0].lower()
if c in 'aeiou':
d.setdefault(c,[]).append(word)
def f2():
d={}
{d.setdefault(word[0].lower(),[]).append(word) for word in words
if word[0].lower() in 'aeiou'}
def f3():
d=defaultdict(list)
{d[word[0].lower()].append(word) for word in words
if word[0].lower() in 'aeiou'}
def f4():
d=functools.reduce(lambda d, w: d.setdefault(w[0], []).append(w[1]) or d,
((w[0].lower(), w) for w in words
if w[0].lower() in 'aeiou'), {})
def f5():
d=defaultdict(list)
for word in words:
c=word[0].lower()
if c in 'aeiou':
d[c].append(word)
制作此基准:
rate/sec f4 f2 f1 f3 f5
f4 11 -- -21.8% -31.1% -31.2% -41.2%
f2 14 27.8% -- -11.9% -12.1% -24.8%
f1 16 45.1% 13.5% -- -0.2% -14.7%
f3 16 45.4% 13.8% 0.2% -- -14.5%
f5 18 70.0% 33.0% 17.2% 16.9% --
带有默认字典的直接循环最快,然后是设置理解并使用setdefault
循环。
感谢您的想法!
答案 0 :(得分:10)
否 - 字典理解旨在通过每次迭代生成非重叠键;他们不支持聚合。对于这个特定的用例,循环是有效完成任务的正确方法(线性时间)。
答案 1 :(得分:4)
不可能(至少容易或直接)使用词典理解。
有可能,但可能滥用语法,使用集合或列表理解:
# your code:
d={}
for word in words:
if word[0].lower() in 'aeiou':
d.setdefault(word[0].lower(),[]).append(word)
# a side effect set comprehension:
index={}
r={index.setdefault(word[0].lower(),[]).append(word) for word in words
if word[0].lower() in 'aeiou'}
print r
print [(k, len(d[k])) for k in sorted(d.keys())]
print [(k, len(index[k])) for k in sorted(index.keys())]
打印:
set([None])
[('a', 17094), ('e', 8734), ('i', 8797), ('o', 7847), ('u', 16385)]
[('a', 17094), ('e', 8734), ('i', 8797), ('o', 7847), ('u', 16385)]
在遍历setdefault()
列表之后,set comprehension生成一个包含words
方法结果的集合。在这种情况下,set([None])
的总和。它还会产生你想要的副作用,产生你的列表。
它不像直接循环结构那样可读(IMHO),应该避免(恕我直言)。它不短,可能不会更快。这是关于Python的更有趣的琐事而不是有用的 - 恕我直言......也许赢得赌注?
答案 2 :(得分:3)
我使用filter
:
>>> words=['abcd','abdef','eft','egg','uck','ice']
>>> index={k.lower():list(filter(lambda x:x[0].lower()==k.lower(),words)) for k in 'aeiou'}
>>> index
{'a': ['abcd', 'abdef'], 'i': ['ice'], 'e': ['eft', 'egg'], 'u': ['uck'], 'o': []}
答案 3 :(得分:1)
这不完全是一个词典理解,但是:
reduce(lambda d, w: d.setdefault(w[0], []).append(w[1]) or d,
((w[0].lower(), w) for w in words
if w[0].lower() in 'aeiou'), {})