我需要做的是将类似以下内容进行转换
{'key1': [1, 2, 3], 'key2': [4, 5, 6]}
转换为
[{'key1': 1, 'key2': 4}, {'key1': 2, 'key2': 5}, {'key1': 3, 'key2': 6}]
值列表的长度可能会有所不同! 最快的方法是什么(最好不使用for循环)?
我需要做的是将类似以下内容进行转换
{'key1': [1, 2, 3], 'key2': [4, 5, 6]}
转换为
[{'key1': 1, 'key2': 4}, {'key1': 2, 'key2': 5}, {'key1': 3, 'key2': 6}]
值列表的长度可能会有所不同! 最快的方法是什么(最好不使用for循环)?
适用于任意数量的键
>>> map(dict, zip(*[[(k, v) for v in value] for k, value in d.items()]))
[{'key2': 4, 'key1': 1}, {'key2': 5, 'key1': 2}, {'key2': 6, 'key1': 3}]
例如:d = {'key3': [7, 8, 9], 'key2': [4, 5, 6], 'key1': [1, 2, 3]}
>>> map(dict, zip(*[[(k, v) for v in value] for k, value in d.items()]))
[{'key3': 7, 'key2': 4, 'key1': 1}, {'key3': 8, 'key2': 5, 'key1': 2}, {'key3': 9, 'key2': 6, 'key1': 3}]
适用于任何数量的值或键的通用解决方案:(Python2.6)
>>> from itertools import izip_longest
>>> d = {'key2': [3, 4, 5, 6], 'key1': [1, 2]}
>>> map(lambda a: dict(filter(None, a)), izip_longest(*[[(k, v) for v in value] for k, value in d.items()]))
[{'key2': 3, 'key1': 1}, {'key2': 4, 'key1': 2}, {'key2': 5}, {'key2': 6}]
如果你没有Python 2.6:
>>> d = {'key2': [3, 4, 5, 6], 'key1': [1, 2]}
>>> map(lambda a: dict(filter(None, a)), map(None, *[[(k, v) for v in value] for k, value in d.items()]))
[{'key2': 3, 'key1': 1}, {'key2': 4, 'key1': 2}, {'key2': 5}, {'key2': 6}]
itit = thedict.iteritems()
k, vs = next(itit)
result = [{k: v} for v in vs]
for k, vs in itit:
for d, v in itertools.izip(result, vs):
d[k] = v
这个数据结构可以被折叠起来,但我对此持怀疑态度,因为这样做可能会影响性能(如果涉及的数据结构非常庞大以至于需要性能优化,则在内存中构建任何额外的辅助结构都可能变得昂贵——我的简单方法特别小心地避免了任何这样的中间结构)。
编辑:另一种选择,特别是当整体数据结构很大,但在某些用例中您可能只需要“部分”“转换”结构时,就是构建一个提供所需接口的类,但是实时生成,而不是一次性完成所有转换(如果原始结构可以更改,并且转换后的结构需要反映原始结构的当前状态等等,则这可能特别有帮助)。
当然,对于这样的目的,非常有帮助的是确定您的下游代码使用“字典列表”的确切功能。例如,假设您实际上只需要“只读”索引(不更改、迭代、切片、排序等):X[x]
必须返回一个字典,其中每个键k映射到一个值,使得(将O
定义为原始字典列表)X[x][k] is O[k][x]
。然后:
class Wrap1(object):
def __init__(self, O):
self.O = O
def __getitem__(self, x):
return dict((k, vs[x]) for k, vs in self.O.iteritems())
__getitem__
也可以“缓存”它返回的字典。class Wrap2(object):
def __init__(self, O):
self.O = O
self.cache = {}
def __getitem__(self, x):
r = self.cache.get(x)
if r is None:
r = self.cache[x] = dict((k, vs[x]) for k, vs in self.O.iteritems())
return r
O
的列表每个都有7个项目,则在x==6
和x==-1
处的缓存可能会出现两个相等的字典;如果这是一个问题,你可以在使用__getitem__
之前,将负数x
归一化为len(self.O)
加上它们来解决。__iter__
方法,容易实现,比如一个简单的生成器...: def __iter__(self, x):
for i in xrange(len(self.O)):
yield self[i]
逐步地,如果您需要列表的更多功能(最坏的情况是,一旦您实现了这个__iter__
,您可以构建self.L = list(self)
- 回到“大爆炸”方法 - 然后,对于任何进一步的请求,将其推迟到self.L
...但是,如果您希望采用这种方法处理特殊方法,您将不得不制作一个特殊的元类,或者使用一些更微妙的技巧,如self.__class__ = list; self[:] = self.L
,然后是适当的del
s;-)。
如果您始终可以使用两个密钥:
[{'key1':a, 'key2':b} for (a,b) in zip(d['key1'], d['key2'])]
d = {'key1': [1, 2, 3], 'key2': [4, 5, 6]}
[dict(zip(d.keys(),i)) for i in zip(*d.values())]
[{'key1': 1, 'key2': 4}, {'key1': 2, 'key2': 5}, {'key1': 3, 'key2': 6}]
>>> a = {'key1': [1, 2, 3], 'key2': [4, 5, 6]}
>>> [dict((key, a[key][i]) for key in a.keys()) for i in range(len(a.values()[0]))]
[{'key2': 4, 'key1': 1}, {'key2': 5, 'key1': 2}, {'key2': 6, 'key1': 3}]
d = {'key1': [1, 2, 3], 'key2': [4, 5, 6]}
keys = d.keys()
vals = zip(*[d[k] for k in keys])
l = [dict(zip(keys, v)) for v in vals]
print l
生成
[{'key2': 4, 'key1': 1}, {'key2': 5, 'key1': 2}, {'key2': 6, 'key1': 3}]
for
。>>> x={'key1': [1, 2, 3], 'key2': [4, 5, 6]}
>>> map(lambda x,y:{'key1':x,'key2':y},x['key1'],x['key2'])
[{'key2': 4, 'key1': 1}, {'key2': 5, 'key1': 2}, {'key2': 6, 'key1': 3}]
list(map( dict, zip(*([(key, val) for val in data[key]] for key in data.keys()))))