python中的通用转置

时间:2014-08-03 17:04:04

标签: python

在python中,表达相对于索引运算符的转置的最短路径是什么?

鉴于某些数据结构x,我希望计算y = transpose(x),以便y[a][b] == x[b][a]

例如,当x是列表列表时,可以使用

轻松实现
y = zip(*x)

但是如果x不是列表,但是例如dict?

{'a': [1,2,3], 'b': [4,5,6], 'c': [7,8,9] } 

编辑:为了澄清,上面的输入应该给出一个行为类似的结构:

[{'a':1, 'b':4, 'c':7}, {'a':2, 'b':5, 'c':8}, {'a':3, 'b':6, 'c':9}]

当提前知道会员列表时,我可以做类似

的事情
[ {'a': z[0], 'b': z[1], 'c': z[2] } for z in zip(x['a'], x['b'], x['c']) ]

充满冗余和不雅。

我可以像这样写一个完全通用的转置:

class Transpose:
    def __init__(self, upper):
        self._upper = upper

    def __getitem__(self, x):
        class Inner:
            def __getitem__(ignore, y):
                return self._upper[y][x]
        return Inner()

但这很冗长且非常不完整(不能正确处理迭代等)。

当然,有一种优雅的方法可以用标准的lib来实现这个目的吗?

3 个答案:

答案 0 :(得分:1)

假设数据结构一致(即所有成员列表长度相同),这将有效:

[{k:v[i] for k,v in x.items()} for i in range(len(x.values()[0]))]

迭代成员列表中的索引并创建一个字典,将每个键映射到该索引处的值。真的,我所做的就是采取你的具体例子并概括它。只要您注意到您在字典中引用了特定键,通常可以使用for k,v in dict.items()上的迭代替换它。

如果您不能依赖数据结构的一致性,那么采用最小长度列表是一个不错的解决方案:

[{k:v[i] for k,v in x.items()} for i in range(min(len(l) for l in x.values()))]

答案 1 :(得分:0)

如果您只是想严格按照自己的方式转换您的词汇列表,那么这将有效:

x = {'a': [1,2,3], 'b': [4,5,6], 'c': [7,8,9] }

[{k:v for k,v in zip(x.keys(),lst)} for lst in x.values()]

结果:

[{'a': 1, 'c': 2, 'b': 3}, {'a': 7, 'c': 8, 'b': 9}, {'a': 4, 'c': 5, 'b': 6}]

至于那些会对任意数据结构进行泛型转换的精辟技巧,我认为这需要更多的工作

答案 2 :(得分:0)

具体来说,假设值是等长的序列:

import itertools as it
d = {'a': [1,2,3], 'b': [4,5,6], 'c': [7,8,9] }
keys = it.repeat(d.keys())
values = it.izip(*d.values())
dT = [dict(it.izip(*thing)) for thing in it.izip(keys, values)]

传递你的身份:

#test
for k, v in d.items():
    for n, item in enumerate(v):
        print 'd[{}][{}] == dT[{}][{}] | {}'.format(k, n, n, k, d[k][n] == dT[n][k])
assert all(d[k][n] == dT[n][k] for k, v in d.items() for n, _ in enumerate(v))

如果值的长度不同,则无效。