2017-04-07 78 views
0
[('a',), ('b',), ('a',)] 

产生将元组列表整理为列表元组字典,其中元组的长度未知?

​​
[('a', 1.0), ('b', 2.0), ('a', 3.0)] 

产生

{'a': ([1.0, 3.0],), 'b': ([2.0],)} 

[('a', 1.0, 0.1), ('b', 2.0, 0.2), ('a', 1.0, 0.3)] 

产生

{'a': ([1.0, 1.0], [0.1, 0.3]), 'b': ([2.0], [0.2])} 

[('a', 1.0, 0.1, 7), ('b', 2.0, 0.2, 8), ('a', 1.0, 0.3, 9)] 

产生

{'a': ([1.0, 1.0], [0.1, 0.3], [7, 9]), 'b': ([2.0], [0.2], [8])} 

我是新来的Python - 这是我想出了。

def Collate(list_of_tuples): 
    if len(list_of_tuples)==0 or len(list_of_tuples[0])==0: 
     return defaultdict(tuple) 
    d = defaultdict(lambda: tuple([] for i in range(len(list_of_tuples[0])-1))) 
    for t in list_of_tuples: 
     d[t[0]] 
     for i,v in enumerate(t): 
      if i>0: 
       d[t[0]][i-1].append(v) 
    return d 

在你想知道我的背景情况下,元组的列表代表的测量。每个元组中的第一项是被测量事物的标识。 后续项目是该事物的不同类型的度量。事物以随机顺序测量,每次都是未知数。 该功能将每个测量值集中在一起进行进一步处理。随着应用的发展,不同类型的测量将被添加。 当客户端代码中的度量类型数量发生变化时,我希望这个Collat​​e函数不必更改。

+0

如果相同ID的元组包含不同数量的测量结果,例如: ('a',1.0,0.1),('b',2.0,0.2),('a',3.0),('a',4.0,0.4)]应该产生什么? – void

回答

0

您可以使用itertools.groupby项目首先使用的字母,然后将其添加到相应的字典键之前收集属于使用zip(*...)相同ID的所有测量:

from itertools import groupby, islice 
import operator 

def collate(lst, f=operator.itemgetter(0)): 
    d = {} 
    for k, g in groupby(sorted(lst, key=f), f): 
     d[k] =() 
     for v in islice(zip(*g), 1, None): 
      d[k] += (list(v),) 
    return d 

测试

lst = [('a',), ('b',), ('a',)] 
print(collate(lst)) 
# {'a':(), 'b':()} 

lst = [('a', 1.0), ('b', 2.0), ('a', 3.0)] 
print(collate(lst)) 
# {'a': ([1.0, 3.0],), 'b': ([2.0],)} 

lst = [('a', 1.0, 0.1, 7), ('b', 2.0, 0.2, 8), ('a', 1.0, 0.3, 9)] 
print(collate(lst)) 
# {'a': ([1.0, 1.0], [0.1, 0.3], [7, 9]), 'b': ([2.0], [0.2], [8])} 

我已经避免使用defaultdict,因为在零测量的情况下(即, [('a',), ('b',), ('a',)])你仍然需要明确地设置键值;这打破了这个收藏的目的。

如果您需要处理缺少的测量,请将zip替换为itertools.zip_longest,并通过明确的fillvalue替换默认的None