Python 以O(n^2/2)形式迭代

Python 以O(n^2/2)形式迭代,python,dictionary,Python,Dictionary,给一本字典: d = {'a':0, 'b': 1, 'c': 2} 我想制作一本新词典,计算d和d的值的乘积 这就是我需要的结果: d = {'a#a': 0, 'a#b': 0, 'a#c': 0, 'b#b' : 1, 'b#c': 2, 'c#c': 4} 但是,我不希望有这样的结果: d = {'a#a': 0, 'a#b': 0, 'a#c': 0, 'b#a' : 0, 'b#b' : 1, 'b#c': 2, 'c#a': 0, 'c#b': 2, 'c#c': 4} 因为

给一本字典:

d = {'a':0, 'b': 1, 'c': 2}
我想制作一本新词典,计算
d
d
的值的乘积

这就是我需要的结果:

d = {'a#a': 0, 'a#b': 0, 'a#c': 0, 'b#b' : 1, 'b#c': 2, 'c#c': 4}
但是,我不希望有这样的结果:

d = {'a#a': 0, 'a#b': 0, 'a#c': 0, 'b#a' : 0, 'b#b' : 1, 'b#c': 2, 'c#a': 0, 'c#b': 2, 'c#c': 4}
因为
c#a
已经被
a#c
计算过了

如果这是一个数组或列表,我会这样做

res=[]
t=[0,1,2]
对于范围内的i(len(t):
对于范围(i)中的j:
res.append(t[i]*t[j])

除了使用字典,我怎样才能做类似的事情呢?

您可以使用dict理解:

dd = {f'{k}#{l}': v*w for k,v in d.items() for l,w in d.items() if k<=l}
>>> {'a#a': 0, 'a#b': 0, 'a#c': 0, 'b#b': 1, 'b#c': 2, 'c#c': 4}
dd={f'{k}{l}:v*w代表k,v在d中。items()代表l,w在d中。items()如果k>{a#a':0,'a#b':0,'a#c':0,'b#b':1,'b#c':2,'c#c':4}
编辑: 如果希望结果按d中的项幻影排序:

d = {'b': 0, 'a': 1, 'c': 2}
dd = {f'{k}#{l}': v*w 
      for i,(k,v) in enumerate(d.items()) 
      for j,(l,w) in enumerate(d.items()) 
      if i<=j}
>>> {'b#b': 0, 'b#a': 0, 'b#c': 0, 'a#a': 1, 'a#c': 2, 'c#c': 4}
d={'b':0,'a':1,'c':2}
dd={f'{k}{l}':v*w
对于枚举(d.items())中的i,(k,v)
对于枚举(d.项()中的j,(l,w)
如果我>>{b#b:0,'b#a:0,'b#c:0,'a#a:1,'a#c:2,'c#c:4}
为什么不使用密码

后一种形式使用生成器,因此不会每次都创建单独的键列表


注意:如果键不可比较(即不是整数、字符串等),则它将不起作用,因此您应该使用例如
if hash(k1)
(它将适用于所有类型的键,因为字典键需要可散列,但键的顺序可能不直观).

Python自带电池,但最干净的方式并不总是显而易见的。您已经拥有了想要内置到
itertools
中的功能

试试这个:

import itertools
result = {f'{k1}#{k2}': d[k1]*d[k2]
   for k1, k2 in itertools.combinations_with_replacement(d, 2)}
itertools.combinations
提供无重复的所有对,
itertools.combinations\u与\u replacement
提供唯一对,包括键相同的对

输出:

>>> print(result)
{'a#a': 0, 'a#b': 0, 'a#c': 0, 'b#b': 1, 'b#c': 2, 'c#c': 4}
{'a#a': 0, 'a#b': 0, 'a#c': 0, 'b#b': 1, 'b#c': 2, 'c#c': 4}

itertools
乐趣无穷:

from itertools import combinations_with_replacement

letter_pairs, number_pairs = (combinations_with_replacement(l, r=2) for l in zip(*d.items()))
result = {letters: number 
          for letters, number in zip(map('#'.join, letter_pairs), 
                                     (a * b for a, b in number_pairs))}

print(result)
输出:

>>> print(result)
{'a#a': 0, 'a#b': 0, 'a#c': 0, 'b#b': 1, 'b#c': 2, 'c#c': 4}
{'a#a': 0, 'a#b': 0, 'a#c': 0, 'b#b': 1, 'b#c': 2, 'c#c': 4}

您可以使用itertools获取组合并形成字典

>>> from itertools import combinations
>>>
>>> d
{'a': 0, 'c': 2, 'b': 1}
>>> combinations(d.keys(),2) # this returns an iterator
<itertools.combinations object at 0x1065dc100>
>>> list(combinations(d.keys(),2)) # on converting them to a list 
[('a', 'c'), ('a', 'b'), ('c', 'b')]
>>> {"{}#{}".format(v1,v2): (v1,v2) for v1,v2 in combinations(d.keys(),2)} # form a dict using dict comprehension, with "a#a" as key and a tuple of two values.
{'a#c': ('a', 'c'), 'a#b': ('a', 'b'), 'c#b': ('c', 'b')}
>>> {"{}#{}".format(v1,v2): d[v1]*d[v2] for v1,v2 in combinations(d.keys(),2)}
{'a#c': 0, 'a#b': 0, 'c#b': 2} # form the actual dict with product as values
>>> {"{}#{}".format(v1,v2):d[v1]*d[v2] for v1,v2 in list(combinations(d.keys(),2)) + [(v1,v1) for v1 in d.keys()]} # form the dict including the self products!
{'a#c': 0, 'a#b': 0, 'a#a': 0, 'b#b': 1, 'c#c': 4, 'c#b': 2}

但是,如果键
'a'
'b'
之后,那就不起作用了。你是什么意思?即使
a
b
之后,它对我来说也非常有效,因为条件失败了。我的意思是,如果输入
'a'
'b'
之后,你就不会在输出字典中看到
'b'
。正如@Austin a在a中指出的那样另一个答案是,这两个都不尊重密钥的原始排序,因此
a#b
将替换
b#a
,即使
b
是在
a
@Acorn之前插入的,OP可能不需要保持顺序,他只希望每对不同的密钥只在结果中出现一次(即
a#b
b#a
但不是两者都有)。
>>> from itertools import combinations_with_replacement
>>> {"{}#{}".format(v1,v2): d[v1]*d[v2] for v1,v2 in combinations_with_replacement(d.keys(),2)}
{'a#c': 0, 'a#b': 0, 'a#a': 0, 'b#b': 1, 'c#c': 4, 'c#b': 2}