2012-01-19 38 views
6

Tôi có một số loại logic dài dòng mà tôi muốn thu gọn với một số hiểu biết.Danh sách kết hợp và đọc hiểu dict

Về cơ bản, tôi có đối tượng dict mà tôi đang đọc có 16 giá trị mà tôi quan tâm. Tôi nhận được chìa khóa mà tôi muốn với sự hiểu biết sau đây:

["I%d" % (i,) for i in range(16)] 

Từ điển nguồn loại trông như thế này:

{ "I0": [0,1,5,2], "I1": [1,3,5,2], "I2": [5,9,10,1], ... } 

Tôi muốn về cơ bản bản đồ từ điển này là một cái gì đó như này:

[ 
    { "I0": 0, "I1": 1, "I2": 5, ... } 
    { "I0": 1, "I1": 3, "I2": 9, ... } 
    ... 
] 

Làm cách nào để ánh xạ những thứ có danh sách và từ điển để chuyển đổi từ điển nguồn vào danh sách từ điển đích?

Trả lời

7

Đây là giải pháp đầy đủ chức năng có thể được áp dụng với kích thước tùy ý.

d = { "I0": [0,1,5,2], "I1": [1,3,5,2], "I2": [5,9,10,1]} 
map(dict, zip(*map(lambda (k, v): map(lambda vv: (k, vv), v), d.iteritems()))) 

xây dựng: (Tôi đang sử dụng ipython và gạch dưới _ có nghĩa là đầu ra trước)

In [1]: d = {'I0': [0, 1, 5, 2], 'I1': [1, 3, 5, 2], 'I2': [5, 9, 10, 1]} 

In [2]: map(lambda (k, v): map(lambda vv: (k, vv), v), _.iteritems()) 
Out[2]: 
[[('I1', 1), ('I1', 3), ('I1', 5), ('I1', 2)], 
[('I0', 0), ('I0', 1), ('I0', 5), ('I0', 2)], 
[('I2', 5), ('I2', 9), ('I2', 10), ('I2', 1)]] 

In [3]: zip(*_) 
Out[3]: 
[(('I1', 1), ('I0', 0), ('I2', 5)), 
(('I1', 3), ('I0', 1), ('I2', 9)), 
(('I1', 5), ('I0', 5), ('I2', 10)), 
(('I1', 2), ('I0', 2), ('I2', 1))] 

In [4]: map(dict, _) 
Out[4]: 
[{'I0': 0, 'I1': 1, 'I2': 5}, 
{'I0': 1, 'I1': 3, 'I2': 9}, 
{'I0': 5, 'I1': 5, 'I2': 10}, 
{'I0': 2, 'I1': 2, 'I2': 1}] 
6

Làm thế nào tôi có thể giải quyết nó:

Thứ nhất, tôi sẽ nhận được cho mỗi chủ chốt một danh sách chứa các bộ dữ liệu, trong đó mục đầu tiên sẽ là khóa và mục thứ hai sẽ là một trong các giá trị từ danh sách:

>>> [ [ (k, i) for i in l] for k, l in d.items() ] 
[[('I1', 1), ('I1', 3), ('I1', 5), ('I1', 2)], 
    [('I0', 0), ('I0', 1), ('I0', 5), ('I0', 2)], 
    [('I2', 5), ('I2', 9), ('I2', 10), ('I2', 1)]] 

Sau đó, tôi sẽ ngang danh sách này, tạo ra một danh sách các hàng chứa mỗi phím tương ứng, sử dụng chức năng zip:

>>> list(zip(*[ [ (k, i) for i in l] for k, l in d.items() ])) 
[(('I1', 1), ('I0', 0), ('I2', 5)), 
(('I1', 3), ('I0', 1), ('I2', 9)), 
(('I1', 5), ('I0', 5), ('I2', 10)), 
    (('I1', 2), ('I0', 2), ('I2', 1))] 

Những danh sách con có thể thông qua như là tham số để các nhà xây dựng dict:

>>> [dict(lp) for lp in zip(*[ [ (k, i) for i in l] for k, l in d.items() ])] 
[{'I0': 0, 'I1': 1, 'I2': 5}, 
{'I0': 1, 'I1': 3, 'I2': 9}, 
{'I0': 5, 'I1': 5, 'I2': 10}, 
{'I0': 2, 'I1': 2, 'I2': 1}] 

Tuy nhiên, trong thực tế, tôi sẽ không bao giờ đề xuất một người làm một việc như vậy chỉ trong một dòng duy nhất:

>>> pairs = [ [ (k, i) for i in l] for k, l in d.items() ] 
>>> transversed = zip(*pairs) 
>>> ds = [dict(t) for t in transversed] 
>>> pprint(ds) 
[{'I0': 0, 'I1': 1, 'I2': 5}, 
{'I0': 1, 'I1': 3, 'I2': 9}, 
{'I0': 5, 'I1': 5, 'I2': 10}, 
{'I0': 2, 'I1': 2, 'I2': 1}] 

Thực ra, tôi wo uld nói rằng tôi đã đăng câu trả lời này chủ yếu là để đề xuất bạn chia giải pháp của mình thành nhiều dòng.

+0

+1 để xây dựng từng bước. Cách tiếp cận của chúng tôi giống nhau ngoại trừ việc tôi đã sử dụng rộng rãi 'bản đồ' :) – qiao

+0

@qiao có, chúng tôi đã áp dụng cùng một cách tiếp cận theo cách trừu tượng hơn. Tôi chỉ có một số ưu tiên cho việc hiểu danh sách nhưng giải pháp của bạn là tuyệt vời. – brandizzi

0

Có ngắn và dễ dàng giải pháp:

keys = data.keys() 
values = data.values() 
transformed = [dict(zip(keys, t)) for t in zip(*values)] 

Mấu chốt ở đây là giá trị transposing ma trận, được thực hiện với zip(*values), sau đó chúng tôi chỉ tái tạo lại dicts.

Các vấn đề liên quan