2009-04-14 15 views
17

से किसी भी उप-स्ट्रिंग के लिए स्ट्रिंग की एक सूची खोजें डेटा के इन 3 सूचियों और कीवर्ड की एक सूची को देखते हुए:एक और सूची

good_data1 = ['hello, world', 'hey, world'] 
good_data2 = ['hey, man', 'whats up'] 
bad_data = ['hi, earth', 'sup, planet'] 
keywords = ['world', 'he'] 

मैं के किसी भी करता है, तो जाँच करने के लिए एक सरल समारोह लिखने के लिए कोशिश कर रहा हूँ कीवर्ड डेटा सूचियों में किसी भी शब्द के सबस्ट्रिंग के रूप में मौजूद हैं। इसे good_data सूचियों के लिए सही और bad_data के लिए गलत होना चाहिए।

मैं कैसे में यह करने के लिए क्या एक अक्षम तरीका प्रतीत हो रहा है पता है:

def checkData(data): 
    for s in data: 
    for k in keywords: 
     if k in s: 
     return True 
    return False 

उत्तर

16

आपके उदाहरण में, बहुत कम वस्तुओं के साथ, यह वास्तव में कोई फर्क नहीं पड़ता। लेकिन अगर आपके पास कई हजार वस्तुओं की सूची है, तो इससे मदद मिल सकती है।

चूंकि आपको कोई परवाह नहीं है कि सूची में कौन सा तत्व कीवर्ड है, तो आप उस समय एक आइटम के बजाय एक बार (एक स्ट्रिंग के रूप में) पूरी सूची स्कैन कर सकते हैं। इसके लिए आपको झूठी सकारात्मकताओं से बचने के लिए कीवर्ड में शामिल होने वाले एक वर्णक चरित्र की आवश्यकता है। मैं इस उदाहरण में नई लाइन का उपयोग करता हूं।

def check_data(data): 
    s = "\n".join(data); 
    for k in keywords: 
     if k in s: 
      return True 

    return False 

मेरे पूरी तरह से अवैज्ञानिक परीक्षण में, मेरे संस्करण ने लगभग 30 सेकंड में 5000 आइटम 100000 बार की एक सूची की जांच की। मैंने 3 मिनट के बाद अपना संस्करण बंद कर दिया - पोस्ट करने की प्रतीक्षा करने से थक गया =

+0

अच्छा समाधान, मैं बिल्कुल यही सोच रहा था। यह regexes की तुलना में बहुत तेज़ होना चाहिए, क्योंकि __contains__ चेक संशोधित बॉयर-मूर के साथ किया जाता है और इस प्रकार विभाजक वर्णों पर अच्छी तरह से छोड़ना चाहिए। –

+0

अच्छा विचार है, और इसमें बड़ी सूचियों पर * बहुत * संकेतक प्रभाव पड़ता है - शायद टॉर्स्टन ने कहा क्योंकि पाइथन उन खोज तालिकाओं का पुन: उपयोग कर सकता है जो उन्हें फेंकने और उन्हें प्रत्येक सूची आइटम के लिए पुनर्निर्माण करने के बजाय बनाता है। मैं अपने समय के आंकड़े अपडेट करूंगा। – Brian

+0

सरणी में शामिल होना एक अच्छा विचार है! मैंने किसी भी() फ़ंक्शन पर एसएलॉट के सुझाव के साथ कॉम्बो में इसका उपयोग करने का निर्णय लिया। धन्यवाद! –

35

आप के लिए

any(k in s for k in keywords) 

देख रहे हैं यह अधिक कॉम्पैक्ट है, लेकिन कम कुशल हो सकता है।

+1

हालांकि यह अधिक कॉम्पैक्ट है, यह बहुत कम पढ़ी जा सकती है। बहुत पर्लिश आईएमएचओ। –

+13

+1 क्योंकि यह मानक पायथनिस्टा idiom – dwc

+0

+1 है यह कीवर्ड की छोटी सूचियों के लिए बहुत ही पाइथोनिक और साफ है –

0

मुझे लगता है कि यह बहुत ही कुशल और स्पष्ट है, हालांकि आप कई घोंसलों से बचने के लिए मानचित्र() का उपयोग कर सकते हैं। मैं बड़े सूचियों के लिए शब्दकोश विचार पर रस्सी से सहमत हूं।

2

आप नियमित अभिव्यक्ति के रूप में कीवर्ड की अपनी सूची बनाकर मामलों में सुधार करने में सक्षम हो सकते हैं।

यह उन्हें समानांतर में परीक्षण करने की अनुमति दे सकता है, लेकिन कीवर्ड पर क्या निर्भर करेगा (उदाहरण के लिए। कुछ काम शुरू करने से प्रत्येक वाक्यांश को खोजने के बजाय "हैलो" और "नरक" के लिए परीक्षण का पुन: उपयोग किया जा सकता है । प्रत्येक शब्द

के लिए आप को क्रियान्वित करते हुए ऐसा कर सकता है:

import re 
keyword_re = re.compile("|".join(map(re.escape, keywords))) 

तब:

>>> bool(keyword_re.search('hello, world')) 
True 
>>> bool(keyword_re.search('hi, earth')) 
False 

(यह वास्तव में एक मैच वस्तु पाया पर वापस आ जाएगी, और कोई नहीं यदि नहीं मिला - यह उपयोगी हो सकता है यदि आपको पता होना चाहिए कि कौन सा कीवर्ड मिलान किया गया है)

हालांकि, यह लाभ कितना (यदि कुछ भी हो) तो आप कीवर्ड पर निर्भर करेंगे। यदि आपके पास केवल एक या दो है, तो अपना वर्तमान दृष्टिकोण रखें। यदि आपके पास बड़ी सूची है, तो यह बेहतर प्रदर्शन करने के लिए यह देखने और प्रोफाइलिंग के लायक हो सकता है।

[संपादित करें] संदर्भ के लिए, दृष्टिकोण आपके उदाहरण के लिए करना बताया गया है:

   good1 good2 good3 bad1 bad2 
original  : 0.206 0.233 0.229 0.390 63.879 
gnud (join) : 0.257 0.347 4.600 0.281 6.706 
regex  : 0.766 1.018 0.397 0.764 124.351 
regex (join) : 0.345 0.337 3.305 0.481 48.666 
जाहिर है इस मामले के लिए

, अपने दृष्टिकोण दूर regex एक से बेहतर प्रदर्शन करती है। चाहे यह हमेशा मामला होगा, कीवर्ड की संख्या और जटिलता, और इनपुट डेटा की जांच की जाएगी। बड़ी संख्या में कीवर्ड, और लंबी सूचियों या शायद ही मिलान करने वाले वाक्यांशों के लिए, regexes बेहतर काम कर सकते हैं, लेकिन समय की जानकारी प्राप्त करें, और शायद पहले भी सरल अनुकूलन (जैसे कि आपकी कीवर्ड सूची के सामने सबसे आम शब्दों को स्थानांतरित करना) को आजमाएं। कभी-कभी सबसे सरल दृष्टिकोण वास्तव में सबसे अच्छा होता है।

[संपादित करें]gnud's solution के साथ तालिका अपडेट की गई, और रेगेक्स लागू करने से पहले एक समान दृष्टिकोण।

good_data3 = good_data2 * 500 # 1000 items, the first of which matches. 
bad_data2 = bad_data * 500  # 1000 items, none of which matches. 

जो विभिन्न शक्तियों और कमजोरियों दिखाई देते हैं: मैं भी 2 नए परीक्षण गयी।जब एक मैच तुरंत मिल जाएगा तो इसमें शामिल होना और भी खराब होता है (क्योंकि सूची में शामिल होने के लिए हमेशा भुगतान किया जाता है, यह रैखिक खोज विधि के लिए सबसे अच्छा संभव मामला है), हालांकि गैर मिलान वाली सूचियों के लिए, यह निष्पादित करता है बेहतर। अधिक बेहतर होता है जब list.case में बड़ी संख्या में आइटम होते हैं)।

+0

इस ब्रायन को समझाने के लिए धन्यवाद। –

4

यदि आपके पास कई कीवर्ड हैं, तो आप एक प्रत्यय पेड़ [1] का प्रयास करना चाहेंगे। तीन डेटा सूचियों के सभी शब्दों को सम्मिलित करें, जो प्रत्येक शब्द को नोड को समाप्त करने में से प्रत्येक सूची को संग्रहीत करता है। फिर आप वास्तव में तेज़ प्रत्येक कीवर्ड के लिए पेड़ पर प्रश्न कर सकते हैं।

चेतावनी: प्रत्यय पेड़ लागू करने के लिए बहुत जटिल हैं!

[1] http://en.wikipedia.org/wiki/Suffix_tree

+0

बेहद अच्छी सलाह। –

+0

हालांकि ध्यान दें कि regexes एक परिमित राज्य मशीन के साथ प्रभावी ढंग से वही करेंगे। मुझे संदेह है कि यह समान रूप से प्रदर्शन करेगा, पाइथन बनाम सी – Brian

+0

में कोड किए जाने के कारण निरंतर कारक द्वारा धीमे को छोड़कर अधिकांश रेगेक्स पुस्तकालयों को * एफएसएम का उपयोग करके लागू नहीं किया जाता है। यह किसी भी रेगेक्स लाइब्रेरी के बारे में सच है जो बैक्रेरेंस के लिए अनुमति देता है। अन्यथा आप बिल्कुल सही होंगे। फिर भी अच्छा बिंदु। – marcog

संबंधित मुद्दे