2012-08-10 23 views
12

मेरे पास d1 और एक सूची l1 है।पायथन शब्दकोश समझ बहुत धीमी

शब्दकोश कुंजी तार हैं, और मान वे ऑब्जेक्ट्स हैं जिन्हें मैंने स्वयं परिभाषित किया है। यदि यह मदद करता है, तो मैं ऑब्जेक्ट का अधिक विस्तार से वर्णन कर सकता हूं लेकिन अभी के लिए, ऑब्जेक्ट्स में एक सूची विशेषता names है, और name के कुछ तत्व l1 में प्रकट हो सकते हैं या नहीं भी हो सकते हैं।

मुझे क्या करना चाहता था शब्दकोश d1, जिसमें कहा तत्व में वस्तु का name विशेषता तत्वों कि l1 में दिखाई देने वाले किसी में नहीं है के किसी भी तत्व फेंक था।

एक छोटी सी उदाहरण के रूप में:

l1 = ['cat', 'dog', 'mouse', 'horse', 'elephant', 
     'zebra', 'lion', 'snake', 'fly'] 

d1 = {'1':['dog', 'mouse', 'horse','orange', 'lemon'], 
     '2':['apple', 'pear','cat', 'mouse', 'horse'], 
     '3':['kiwi', 'lime','cat', 'dog', 'mouse'], 
     '4':['carrot','potato','cat', 'dog', 'horse'], 
     '5':['chair', 'table', 'knife']} 

तो जिसके परिणामस्वरूप शब्दकोश किया जाएगा और अधिक या कम एक ही है, लेकिन प्रत्येक सूची के तत्वों फल और सब्जियों को छोड़कर 4 करने के लिए 1 से कुंजी-मान जोड़ों हो जाएगा, और इसमें 5 वां कुंजी-मान बराबर नहीं होगा क्योंकि फर्नीचर मानों में से कोई भी l1 में दिखाई नहीं देता है।

ऐसा करने के लिए मैं एक नेस्टेड सूची/समझ शब्दकोश जो इस तरह देखा इस्तेमाल किया:

d2 = {k: [a for a in l1 if a in d1[k]] for k in d1.keys()} 
print(d2) 

>>>>{'1': ['dog', 'mouse', 'horse'], 
    '3': ['cat', 'dog', 'mouse'], 
    '2': ['cat', 'mouse', 'horse'], 
    '5': [], 
    '4': ['cat', 'dog', 'horse']} 

d2 = {k: v for k,v in d2.iteritems() if len(v)>0} 
print(d2) 

>>>>{'1': ['dog', 'mouse', 'horse'], 
    '3': ['cat', 'dog', 'mouse'], 
    '2': ['cat', 'mouse', 'horse'], 
    '4': ['cat', 'dog', 'horse'],} 

यह काम करने के लिए लगता है, लेकिन बड़ी शब्दकोशों, 7000 मदों के लिए, इसके माध्यम से काम करने के लिए लगभग 20 सेकंड लेता है। अपने आप में और भयानक नहीं, लेकिन मुझे इसे एक लूप के अंदर करने की ज़रूरत है जो 10,000 गुना फिर से शुरू हो जाएगी, इसलिए वर्तमान में यह संभव नहीं है। इसे जल्दी से कैसे करें इस पर कोई सुझाव?

+1

हर किसी के लिए नोट: वह 'itertitems' के उपयोग के कारण अजगर 2.7 नहीं 3 उपयोग कर रहा है, न दें' प्रिंट() 'मूर्ख आप – jamylak

+0

पायथन 2.7 में समझदारी है? – Claudiu

+0

@ क्लाउडियो हां उन्हें पूरी तरह से प्रतिलिपि बनाने योग्य उदाहरण – jamylak

उत्तर

13

आप l1 सूची के साथ शब्दकोश मानों में होने वाली प्रत्येक सूची के सेट चौराहे को प्रभावी ढंग से कंप्यूटिंग कर रहे हैं। सेट चौराहे के लिए सूचियों का उपयोग करना रैखिक खोजों की वजह से अक्षम है। आपको l1 को एक सेट में बदलना चाहिए और set.intersection() का उपयोग करना चाहिए या इसके बजाय सदस्यता परीक्षण सेट करना चाहिए (इस पर निर्भर करता है कि परिणाम स्वीकार्य है कि परिणाम फिर से सेट है)।

पूर्ण कोड ऐसा दिखाई दे सकता:

l1 = set(l1) 
d2 = {k: [s for s in v if s in l1] for k, v in d1.iteritems()} 
d2 = {k: v for k, v in d2.iteritems() if v} 
दो शब्दकोश comprehensions के बजाय

, यह भी एक भी for पाश यहाँ उपयोग करने के लिए बेहतर हो सकता है:

l1 = set(l1) 
d2 = {} 
for k, v in d1.iteritems(): 
    v = [s for s in v if s in l1] 
    if v: 
     d2[k] = v 
+0

पूर्ण दक्षता के लिए मैं आपके पहले कोड को '>>> d2 = ((के, [एस में एस में v के लिए v1 में] के लिए बदल दूंगा) के लिए v, v1.iteritems() में >>> d2 = {के: वी के लिए वी, वी 2 में v अगर v} '। – jamylak

+0

@jamylak: क्या आपको लगता है कि यह 'लूप' की तुलना में काफी तेज होगा? मैं एक के लिए सोचता हूं कि यह कम से कम ngoicably uglier है। :) –

+0

वैसे यह आपके पहले कोड के लिए आपके पास कोड से अधिक कुशल होगा जो अभी डी 2 के माध्यम से चलाएगा। दूसरे के बारे में निश्चित नहीं है, 'टाइमिट' – jamylak

4

मुद्दा नहीं है श्रोताओं की समझ, लेकिन उसमें घोंसला सूची समझ। आप हर बार एक ही कुंजी पर फिर से चल रहे हैं। इस तरह की चीज सेट के साथ बेहतर है।

s1 = set(l1) 
d2 = {k: list(s1.intersection(v)) for k, v in d1.items()} 
+2

अधिक दक्षता उपयोग के लिए 'iteritems' – jamylak

+1

यह अधिक कुशल होगा यदि' d1' और 'd2' में मान सेट होने की अनुमति है। –

0

उपयोग set:

>>> l1 = ['cat', 'dog', 'mouse', 'horse', 'elephant', 
     'zebra', 'lion', 'snake', 'fly'] 
>>> d1 = {'1':['dog', 'mouse', 'horse','orange', 'lemon'], 
     '2':['apple', 'pear','cat', 'mouse', 'horse'], 
     '3':['kiwi', 'lime','cat', 'dog', 'mouse'], 
     '4':['carrot','potato','cat', 'dog', 'horse'], 
     '5':['chair', 'table', 'knife']} 
>>> l1_set = set(l1) 
>>> d2 = dict((k, set(d1[k]) & l1_set) for k in d1.keys()) 
>>> d2 
{'1': set(['horse', 'mouse', 'dog']), '3': set(['mouse', 'dog', 'cat']), '2': set(['horse', 'mouse', 'cat']), '5': set([]), '4': set(['horse', 'dog', 'cat'])} 
>>> d2 = dict((k, v) for k,v in d2.iteritems() if v) 
>>> d2 
{'1': set(['horse', 'mouse', 'dog']), '3': set(['mouse', 'dog', 'cat']), '2': set(['horse', 'mouse', 'cat']), '4': set(['horse', 'dog', 'cat'])} 
0

आप एक set करने के लिए l1 बदलने और थोड़ा dict समझ को संशोधित करते हैं, तो आप इस काम कर रहे लगभग तीन गुना तेजी से प्राप्त कर सकते हैं:

l1 = set(['cat', 'dog', 'mouse', 'horse', 'elephant', 
     'zebra', 'lion', 'snake', 'fly']) 

d1 = {'1':['dog', 'mouse', 'horse','orange', 'lemon'], 
     '2':['apple', 'pear','cat', 'mouse', 'horse'], 
     '3':['kiwi', 'lime','cat', 'dog', 'mouse'], 
     '4':['carrot','potato','cat', 'dog', 'horse'], 
     '5':['chair', 'table', 'knife']} 

d2 = {k: [a for a in d1[k] if a in l1] for k in d1.keys()} 
print(d2) 

यहाँ है कैसे आप प्रदर्शन को बेंचमार्क कर सकते हैं:

import timeit 

t = timeit.Timer(
    "d2 = {k: [a for a in l1 if a in d1[k]] for k in d1.keys()}", 
    "from __main__ import (d1, l1)", 
    ) 
print "%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000) 

t = timeit.Timer(
    'd2 = {k: [a for a in d1[k] if a in l1] for k in d1.keys()}', 
    "from __main__ import (d1, l1)", 
    ) 
print "%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000) 

मुझे लगता है कि आपके पास d1 पर नियंत्रण नहीं है, और फ़िल्टरिंग से पहले सेट करने के लिए d1 के सभी मानों को परिवर्तित करना बहुत धीमा है।

1
l1 = ['cat', 'dog', 'mouse', 'horse', 'elephant', 
     'zebra', 'lion', 'snake', 'fly'] 

d1 = {'1':['dog', 'mouse', 'horse','orange', 'lemon'], 
     '2':['apple', 'pear','cat', 'mouse', 'horse'], 
     '3':['kiwi', 'lime','cat', 'dog', 'mouse'], 
     '4':['carrot','potato','cat', 'dog', 'horse'], 
     '5':['chair', 'table', 'knife']} 

def gen_items(valid_name_set, d): 
    for k, v in d.iteritems(): 
     intersection = valid_name_set.intersection(v) 
     if intersection: # not empty 
      yield (k, intersection) 

print dict(gen_items(set(l1), d1)) 

आउटपुट:

{'1': set(['dog', 'horse', 'mouse']), 
'2': set(['cat', 'horse', 'mouse']), 
'3': set(['cat', 'dog', 'mouse']), 
'4': set(['cat', 'dog', 'horse'])} 

वैकल्पिक रूप से:

from itertools import ifilter 
from operator import itemgetter 
set_l1 = set(l1) 
d2 = dict(ifilter(itemgetter(1), 
        ((k, set_l1.intersection(v)) for k, v in d1.iteritems()))) 
संबंधित मुद्दे