2009-11-22 72 views
9

gì tôi cần phải làm là để chuyển đổi một cái gì đó như thế nàyđiển Chia danh sách thành danh sách các từ điển

{'key1': [1, 2, 3], 'key2': [4, 5, 6]} 

vào

[{'key1': 1, 'key2': 4}, {'key1': 2, 'key2': 5}, {'key1': 3, 'key2': 6}] 

Chiều dài của danh sách giá trị có thể thay đổi! Cách nhanh nhất để làm điều này (tốt nhất là không có vòng lặp) là gì?

+0

Bạn có thể muốn làm rõ câu hỏi của bạn một chút ... Tôi đã mất một thời gian để hiểu những gì bạn muốn từ ví dụ của bạn: chuyển đổi một bản đồ với hai phím (key1 , key2) mỗi danh sách có các giá trị (có cùng độ dài, nhưng khác nhau) cho một danh sách các cặp vợ chồng và trong cặp vợ chồng tại vị trí i, key1 và key2 được đặt thành phần tử thứ i của danh sách tương ứng. Là nó? –

+0

Tại sao lại có niềm đam mê khi làm việc đó mà không có vòng lặp? Đó là một hạn chế ngu ngốc. – jcdyer

+0

nó không phải là phải, tôi đã viết "tốt hơn". Suy nghĩ có thể có một cách nhanh chóng để làm điều này (một số chức năng ma thuật mà tôi chưa biết); –

Trả lời

11

trình cho bất kỳ số lượng các phím

>>> 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}] 

Ví dụ :

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}] 

Một giải pháp chung mà hoạt động trên bất kỳ số lượng các giá trị hoặc các phím: (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}] 

Và nếu bạn không có python2.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}] 
2

Nếu luôn có hai phím bạn có thể sử dụng:

[{'key1':a, 'key2':b} for (a,b) in zip(d['key1'], d['key2'])] 
1
>>> 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}] 
+0

độ dài của danh sách giá trị có thể thay đổi . phạm vi (3) là khá liên tục. – zlack

1
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 

sản xuất

[{'key2': 4, 'key1': 1}, {'key2': 5, 'key1': 2}, {'key2': 6, 'key1': 3}] 
5

Giả sử số lượng các phím, và các giá trị cho mỗi khoá, đều tùy ý và không xác định trước, nó đơn giản nhất để có được kết quả với các vòng lặp, tất nhiên:

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 

Nó có thể bị sụp đổ, nhưng tôi không chắc chắn về hiệu quả của việc thực hiện (nếu cấu trúc dữ liệu có liên quan quá lớn để đảm bảo tối ưu hóa hiệu suất, xây dựng thêm bất kỳ cấu trúc phụ nào trong bộ nhớ tốn kém - cách tiếp cận đơn giản này của tôi là đặc biệt cẩn thận để tránh bất kỳ cấu trúc trung gian nào như vậy).

Chỉnh sửa: một lựa chọn khác, đặc biệt thú vị nếu cấu trúc dữ liệu tổng thể rất lớn nhưng trong một số trường hợp sử dụng, bạn chỉ cần "bit và miếng" của cấu trúc "được chuyển đổi", là xây dựng một lớp cung cấp giao diện bạn yêu cầu, nhưng thay vào đó là "trên bay", thay vì trong một "cú đánh lớn", "một lần và cho tất cả" chuyển đổi (điều này có thể đặc biệt hữu ích nếu cấu trúc ban đầu có thể thay đổi và cấu trúc được chuyển đổi cần phản ánh trạng thái hiện tại của bản gốc, v.v.).

Tất nhiên, với mục đích như vậy, rất hữu ích để xác định chính xác những tính năng của "danh sách từ điển" mà mã hạ lưu của bạn sẽ sử dụng. Giả sử ví dụ rằng tất cả những gì bạn cần là lập chỉ mục "chỉ đọc" (không thay đổi, lặp lại, cắt, sắp xếp, ...): X[x] phải trả về một từ điển trong đó mỗi khóa k ánh xạ tới một giá trị như vậy (caling O từ điển ban đầu của danh sách) X[x][k] is O[k][x]. Sau đó:

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()) 

Nếu bạn không thực sự cần cấu trúc bọc để theo dõi những thay đổi với một bản gốc, sau đó __getitem__ rất có thể cũng "cache" dict nó trở về:

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 

Lưu ý rằng cách tiếp cận này có thể kết thúc với một số bản sao trong bộ nhớ cache, ví dụ: nếu danh sách của O có 7 mục, bộ nhớ cache tại x==6x==-1 có thể kết thúc với hai chữ cái bằng nhau; nếu đó là một vấn đề bạn có thể, ví dụ, bình thường hóa tiêu cực x s trong __getitem__ bằng cách thêm len(self.O) cho họ trước khi tiếp tục.

Nếu bạn cũng cần lặp lại, cũng như chỉ mục đơn giản này, điều đó không quá khó: chỉ cần thêm phương thức __iter__, dễ dàng triển khai, ví dụ: như một máy phát điện đơn giản ...:

def __iter__(self, x): 
    for i in xrange(len(self.O)): 
     yield self[i] 

Và vân vân, từng bước, nếu và khi bạn cần ngày càng nhiều các chức năng của một danh sách (lúc tồi tệ nhất, một khi bạn đã thực hiện điều này __iter__, bạn có thể xây dựng self.L = list(self) - quay trở lại các "vụ nổ lớn" cách tiếp cận - và, đối với bất kỳ yêu cầu nào khác, hãy gửi đến self.L ... nhưng bạn sẽ phải tạo một metaclass đặc biệt nếu bạn muốn sử dụng phương pháp đó cho các phương pháp đặc biệt hoặc sử dụng một số mẹo phụ như self.__class__ = list; self[:] = self.L đã theo dõi theo thích hợp del s ;-).

1
list(map(dict, zip(*([(key, val) for val in data[key]] for key in data.keys())))) 
1

Nếu không có vòng lặp for, quy trình nội bộ của bản đồ được lặp lại trên thực tế, chỉ cần không có từ khóa 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}] 
0

Làm thế nào?

d = {'key1': [1, 2, 3], 'key2': [4, 5, 6]} 
[dict(zip(d.keys(),i)) for i in zip(*d.values())] 

Returns:

[{'key1': 1, 'key2': 4}, {'key1': 2, 'key2': 5}, {'key1': 3, 'key2': 6}] 
Các vấn đề liên quan