我遇到以下问题:我创建了一个字典,其中的键是ID(从0到N),值是一个或多个数字的列表。
D = dict()
D[0] = [1]
D[1] = [2]
D[2] = [0]
OR:
D = dict()
D[0] = [1, 2]
D[1] = [1, 2]
D[2] = [0]
当存储在字典中的列表具有多个值时,始终表示此列表位于2个不同的键下。我现在想要的是将两个字典都转换成这样:
D = dict()
D[0] = 1
D[1] = 2
D[2] = 0
对于第一个来说,很简单,该函数将用列表中的第一个值替换dict的值:
def transform_dict(D):
for key, value in D.items():
D[key] = value[0]
return D
但是,在第二种情况下,该函数必须为其中一个键分配一个值,而第二个键分配另一个值。例如,可以为键“ 0”分配值“ 1”或“ 2”;键“ 1”将分配给另一个。
我正在为这个简单的问题而苦苦挣扎,但我没有找到有效执行此操作的方法。你有什么主意吗?
编辑:解释n°2
初始字典可以具有以下格式:
D[key1] = [val1]
D[key2] = [val2]
D[key3] = [val3, val4]
D[key4] = [val3, val4]
如果值列表由一个以上的元素组成,则意味着字典中存在另一个具有相同值列表(键3和键4)的键。
目标是将该字典转换为:
D[key1] = val1
D[key2] = val2
D[key3] = val3
D[key4] = val4
其中val3和val4以任何方式归属于key3和key4(我不在乎哪一个与哪个键一起使用)。
EDIT2:示例:
# Input dict
D[0] = [7]
D[1] = [5]
D[2] = [4]
D[3] = [1, 2, 3]
D[4] = [6, 8]
D[5] = [1, 2, 3]
D[6] = [1, 2, 3]
D[7] = [6, 8]
#Output
D[0] = 7
D[1] = 5
D[2] = 4
D[3] = 1
D[4] = 6
D[5] = 2
D[6] = 3
D[7] = 8
答案 0 :(得分:2)
您还可以创建行为类似于字典的类。这样,您不需要任何其他功能即可“清理”字典,而可以即时解决它:)
工作原理:
我们扩展DECLARE @b1 varbinary(16) = convert(varbinary(16), newid()),
@b2 varbinary(16) = convert(varbinary(16), newid())
SELECT CASE WHEN @b1 > @b2 THEN '@b1 is bigger' ELSE '@b2 is bigger' END
并覆盖标准字典函数collections.abc.Mapping
,__getitem__
和__setitem__
。我们使用__iter__
保存实际的字典。
我们使用第二个字典self._storage
来跟踪尚未解析的键。在上面的示例中,它例如具有条目_unresolved
。
我们使用辅助功能(1, 2, 3): [4, 5]
来检查是否_resolve()
。在您分配len((1,2,3)) == len([4,5])
时,此长度相等,并且项目也分配给D[6]
。
试图在代码中添加注释。
self._storage
然后开始:
from collections.abc import Mapping
from collections import defaultdict
class WeirdDict(Mapping):
def __init__(self, *args, **kw):
self._storage = dict() # the actual dictionary returned
self._unresolved = defaultdict(list) # a reversed mapping of the unresolved items
for key, value in dict(*args, **kw).items():
self._unresolved_vals[value].append(key)
self._resolve()
def __getitem__(self, key):
return self._storage[key]
def __setitem__(self, key, val):
""" Setter. """
if type(val) == int:
self._storage[key] = val
elif len(val) == 1:
self._storage[key] = val[0]
elif key not in self._storage:
self._unresolved[tuple(val)].append(key)
self._resolve()
def _resolve(self):
""" Helper function - checks if any keys can be resolved """
resolved = set()
for val, keys in self._unresolved.items(): # left to resolve
if len(val) == len(keys): # if we can resolve (count exhausted)
for i, k in enumerate(keys):
self._storage[k] = val[i]
resolved.add(val)
# Remove from todo list
for val in resolved:
del self._unresolved[val]
def __iter__(self):
return iter(self._storage)
def __len__(self):
return len(self._storage)
答案 1 :(得分:1)
我不确定这是否是最有效的方法,但这似乎是一种方法:
in_dict = dict()
in_dict[0] = [7]
in_dict[1] = [5]
in_dict[2] = [4]
in_dict[3] = [1, 2, 3]
in_dict[4] = [6, 8]
in_dict[5] = [1, 2, 3]
in_dict[6] = [1, 2, 3]
in_dict[7] = [6, 8]
out_dict = dict()
out_dict[0] = 7
out_dict[1] = 5
out_dict[2] = 4
out_dict[3] = 1
out_dict[4] = 6
out_dict[5] = 2
out_dict[6] = 3
out_dict[7] = 8
def weird_process(mapping):
result = dict()
for key, val in mapping.items():
if len(val) == 1:
result[key] = val[0]
elif key not in result: # was: `else:`
# find other keys having the same value
matching_keys = [k for k, v in mapping.items() if v == val]
for i, k in enumerate(matching_keys):
result[k] = val[i]
return result
weird_process(in_dict) == out_dict
# True
编辑:我对代码进行了一些简化。
EDIT2:通过跳过已处理的元素,我提高了效率
EDIT3
一种更快的方法是使用输入键的临时副本,通过在使用完输入后立即使用输入来减少内部循环:
def weird_process(mapping):
unseen = set(mapping.keys())
result = dict()
for key, val in mapping.items():
if len(val) == 1:
result[key] = val[0]
elif key not in result:
# find other keys having the same value
matching_keys = [k for k in unseen if mapping[k] == val]
for i, k in enumerate(matching_keys):
result[k] = val[i]
unseen.remove(k)
return result