2009-11-22 21 views
9

की सूची में सूचियों का विभाजन शब्दकोश क्या मैं क्या करने की जरूरत इसशब्दकोशों

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

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

मूल्य सूचियों भिन्न हो सकते हैं की लंबाई की तरह कुछ कन्वर्ट करने के लिए है! ऐसा करने का सबसे तेज़ तरीका क्या है (अधिमानतः लूप के बिना)?

+0

आप अपने प्रश्न थोड़ा स्पष्ट करने के लिए चाहते हो सकता है ... यह मुझे कुछ समय लगा समझने के लिए आप अपने उदाहरण से हैं: दो कुंजी के साथ एक नक्शा परिवर्तित (कुंजी 1 , key2) प्रत्येक जोड़े को एक सूची में मूल्यों की सूची (समान, लेकिन अलग-अलग लंबाई) की सूची के साथ, और जोड़े में स्थिति में, key1 और key2 उनकी संबंधित सूची के ith तत्व पर सेट है। क्या यही है? –

+0

लूप के बिना इसे करने का आकर्षण क्यों? यह एक बेवकूफ बाधा है। – jcdyer

+0

यह जरूरी नहीं था, मैंने "अधिमानतः" लिखा था। सोचा कि ऐसा करने के लिए एक त्वरित पायथनिक तरीका हो सकता है (कुछ जादू कार्य जो मुझे अभी तक नहीं पता था;)) –

उत्तर

11

वर्क्स के बिना

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

और तुम 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

आप अगर वहाँ हमेशा दो चाबियाँ हैं का उपयोग कर सकते हैं:

[{'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

मूल्य सूची की लंबाई अलग-अलग हो सकती है । रेंज (3) सुंदर स्थिर है। – 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 

कुंजियों की संख्या मान लिया जाये कि पैदा करता है

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

, और कुंजी प्रति मूल्यों, दोनों ऐच्छिक हैं और अज्ञात एक अज्ञात, लूप के साथ परिणाम प्राप्त करना सबसे आसान है, बेशक:

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] को एक शब्दकोश वापस करना होगा जिसमें प्रत्येक कुंजी के नक्शे को किसी मान के लिए मानचित्र किया जाए (कैलिंग 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 पर दो बराबर डिक्ट्स के साथ समाप्त हो सकता है; यदि यह एक समस्या है, तो उदाहरण के लिए, आगे बढ़ने से पहले len(self.O) जोड़कर __getitem__ में नकारात्मक x एस को सामान्यीकृत कर सकते हैं।

यदि आपको पुनरावृत्ति की आवश्यकता है, साथ ही साथ यह सरल अनुक्रमण भी है, तो यह बहुत कठिन नहीं है: बस __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 एस ;-) द्वारा।

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

पाश के लिए बिना, नक्शे के आंतरिक प्रक्रिया वास्तव में पुनरावृत्ति है, बस कीवर्ड कुंजी के किसी भी संख्या के लिए 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

कैसे?

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}] 
संबंधित मुद्दे