[英]Comparing dictionaries with fewer loops
我有一本字典,其中包含字典作为其值。 以下是我的字典的结构
myD = {'key1': {'x' : 123, 'y' : 432},
'key2': {'x' : 456, 'y' : 565},
'key3': {'x' : 789, 'y' : 420},
...}
我需要比较这个字典的值(你可以看到我在每个值中都有类似的字典结构)并生成以下输出。 策略遍历值字段中的每个字典,并选择给定键的最小值并将其插入到新字典中。 例如,如果我们从值字典中考虑x键,则它最少为123
。 所以我的新词典应该有x:123
。
my_newD = {'x' : 123, 'y' : 420, ...}
我可以使用3 for循环来实现这一点,但有没有任何优雅的方法来做更少的for循环?
我想出了两个循环:
my_newD = {key: min(item[key] for item in myD.values())
for key in next(iter(myD.values()))}
编辑:根据@Andriy Makukha的建议,删除了对外循环中'key1'
显式依赖
编辑2:用next(iter(myD.values()))
替换myD[list(myD.keys())[0]]
。
不确定哪一个不那么神秘,但使用next
并且iter
看起来效率更高。
感谢Leo K指出它!
这是使用collections.defaultdict
的O(n)解决方案:
from collections import defaultdict
myD = {'key1': {'x' : 123, 'y' : 432},
'key2': {'x' : 456, 'y' : 565},
'key3': {'x' : 789, 'y' : 420}}
# initialise defaultdict of lists
d = defaultdict(list)
# iterate input dictionary and add values to lists
for v1 in myD.values():
for k2, v2 in v1.items():
d[k2].append(v2)
# calculate minimum
res = {k: min(v) for k, v in d.items()}
print(res)
{'x': 123, 'y': 420}
两个循环:
myD = {'key1': {'x' : 123, 'y' : 432},
'key2': {'x' : 456, 'y' : 565},
'key3': {'x' : 789, 'y' : 420}}
resD = {}
for key in myD:
subD = myD[key]
for k in subD:
resD[k] = min(resD[k], subD[k]) if k in resD else subD[k]
print (resD)
输出:
{'x': 123, 'y': 420}
pandas
另一种可能性(在优雅方面更好):
import pandas as pd
my_newD = pd.DataFrame(myD).min(axis=1).to_dict()
这是我在O(n)中的解决方案
>>> from itertools import accumulate
>>> min_t = lambda *t: [min(r) for r in zip(*t)]
>>> *_, min_vals = accumulate([v.values() for k,v in myD.items()], min_t)
>>> keys = next(iter(myD.values())).keys()
>>> dict(zip(keys, vals))
{'x': 123, 'y': 420}
>>>
说明
>>> from itertools import accumulate
>>>
>>> myD = {'key1': {'x': 123, 'y': 432}, 'key2': {'x': 456, 'y': 565}, 'key3': {'x': 789, 'y': 420}}
>>>
>>> # Define a func to find min of tuples
>>> def min_t(*t):
... return [min(r) for r in zip(*t)]
...
>>> # Build the tuple
>>> t = (v.values() for k,v in myD.items())
>>> *_, min_vals = accumulate(t, min_t)
>>> min_vals
[123, 420]
>>>
>>> keys = next(iter(myD.values())).keys()
>>> keys
dict_keys(['x', 'y'])
>>>
>>>
>>> dict(zip(keys, vals))
{'x': 123, 'y': 420}
>>>
或者在单行中
>>> from itertools import accumulate
>>> from collections import deque
>>> dict(zip(next(iter(myD.values())).keys(), deque(accumulate((v.values() for k,v in myD.items()), lambda *t: [min(r) for r in zip(*t)]), maxlen=1).pop()))
{'x': 123, 'y': 420}
flat_d = [v[1] for v in myD.items()]
{"x":min([v["x"] for v in flat_d ]),"y":min([v["y"] for v in flat_d ])}
此动态代码适用于任意数量的变量 。 其复杂度为O(M * N),其中M =找到最小值的变量数,N = myD
的键myD
# here, M = 3, N = 3
myD = {'key1': {'x' : 123, 'y' : 432, 'z': 100},
'key2': {'x' : 456, 'y' : 565, 'z': 99},
'key3': {'x' : 789, 'y' : 420, 'z': 250}}
firstKey = "key1"
# assume firstKey has all the minimum entries
# use it as a base to compare all other values to
minD = {}
for (k,v) in myD[firstKey].items():
minD[k] = v
items = myD.items()
# find minimum of variable x, then y, then z
for variable in minD:
print "Finding minimum of " + variable
for key, dictionary in items:
keyVal = dictionary[variable]
if minD[variable] > keyVal:
minD[variable] = keyVal
print minD # {'y': 420, 'x': 123, 'z': 99}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.