2010-01-26 8 views
10

में एक ऐरेलिस्ट को कुशलतापूर्वक फ़िल्टर करें, मैं एक एंड्रॉइड ऐप (एंड्रॉइड 1.6) विकसित कर रहा हूं, लेकिन यह शायद एक सामान्य जावा प्रश्न है।जावा/एंड्रॉइड

मैं लगभग 10,000 वस्तुओं

की एक ArrayList है वस्तुओं 3 तार (firstName, middleName, lastName) होते हैं।

उपयोगकर्ता को एंड्रॉइड पर "खोज बॉक्स" के साथ प्रस्तुत किया जाता है जहां वे नाम के हिस्से में टाइप करके एक विशेष "ऑब्जेक्ट" खोज सकते हैं।

मेरे पास एक कक्षा है (जिसे मैं फिलटेरर कहता हूं) जो मिलान करने वाली वस्तुओं के लिए 10,000 की सूची के माध्यम से खोज करता है और फिर उन्हें "उपन्यासकार" के रूप में लौटाता है।

खोज थोड़ी सी धीमी है (विशेष रूप से एंड्रॉइड हैंडसेट पर) और मुझे यकीन है कि मैं सबसे कुशल तरीके से खोज/फ़िल्टरिंग नहीं कर रहा हूं।

क्या किसी के पास मेरी खोज को गति देने के बारे में कोई सुझाव है? मेरा कोड नीचे है। एक माध्यमिक "मास्टरलिस्ट" के खिलाफ खोज करने की एक संभावना है जिसमें पहले से ही लोअरकेस और समेकित में जानकारी का हर टुकड़ा है ... लेकिन इस खोज को बेहतर बनाने के अतिरिक्त तरीके भी हो सकते हैं जो मदद भी करेंगे।

टीआईए !!

public void filterNames() { 
    this.filteredList.clear(); 
    String sv = this.searchString.toString.trim().toLowerCase(); // search value 
    for (int i = 0; i < this.masterList.size(); i++) { 
    MyObject d = this.masterList.get(i); 
    String fn = d.getFirstName().toString().toLowerCase(); 
    String mn = d.getMiddleName().toString().toLowerCase(); 
    String ln = d.getLastName().toString().toLowerCase(); 

    if (fn.indexOf(sv) >= 0 || 
     md.indexOf(sv) >= 0 || 
     ln.indexOf(sv) >= 0) { 
     this.currentList.add(d); 
    } 
    } 
} 
+0

यहाँ समान समस्या के लिए देखो: http://stackoverflow.com/questions/2085445/fast-index-for- इसमें स्ट्रिंग को सी ++ से दिमाग में पूछा जाता है, लेकिन सामान्य समाधान (डेटा संरचनाएं और एल्गोरिदम) भाषा स्वतंत्र होती है। – WildWezyr

उत्तर

6

हाँ, यह निश्चित रूप से दर्दनाक है प्रत्येक पाश यात्रा के लिए लोअर केस कई वस्तुओं के लिए (प्लस एक संभवतः वे अनावश्यक toString?), और भी बुरा व्यवहार हर यात्रा — के लिए list.size() कॉल करने के लिए है कि मूल्य पाश से पहले कैश की गई किया जाना चाहिए शुरू होता है।

वैसे भी, यदि आप इस डेटा के साथ काम कर रहे हैं, तो क्या कोई कारण है कि आप संग्रहण के लिए SQLite डेटाबेस का उपयोग नहीं कर रहे हैं और CursorAdapter का उपयोग करके अपनी सूची को प्रदर्शित/फ़िल्टर कर रहे हैं?

यह इस आकार के कुछ को लागू करने का अनुशंसित तरीका होगा।

+0

क्या SQLite (या अन्य SQL DBMS) वास्तव में infix खोज के साथ मदद करेगा? क्या इसके लिए विशेष प्रकार की अनुक्रमणिका है? – WildWezyr

+1

स्थानीय पाश "आकार" चर एक जावा ओल्ड वाइव्स टेल हैं, जो "अंतिम" घोषित विधियों की तरह हैं। JVM आकार() कॉल को रेखांकित करेगा और आपको कोई प्रदर्शन लाभ दिखाई नहीं देगा। –

+3

@Civil अवज्ञाकारी: यह अधिकांश JVMs के लिए सच है, लेकिन एंड्रॉइड उपकरणों पर Dalvik VM के लिए जरूरी नहीं है। अधिक जानकारी के लिए http://developer.android.com/intl/fr/guide/practices/design/performance.html#cache_fields देखें। –

2

शायद आप कुछ गति के लिए कुछ जगह व्यापार कर सकते हैं? अपने डेटा के लिए इंडेक्स का कुछ रूप बनाएं?

उदाहरण के लिए:

  1. सभी "MyObject" रों जहां नाम का एक हिस्सा वर्ण के साथ एक चरित्र (a-z) की सूची बनाएं (विशेष वर्ण के बारे में पता होना!)। प्रत्येक प्रविष्टि के लिए "MyObject" की संख्या
  2. यदि कोई उपयोगकर्ता किसी प्रश्न में टाइप करता है, तो अलग-अलग वर्णों को देखें और केवल छोटी प्रविष्टियों के साथ सूची खोजें।

बेशक किसी नाम के अतिरिक्त आपको इसे इंडेक्स में जोड़ने की आवश्यकता होगी।

0

थोड़ा और शोध करने के बाद मुझे पता चला है कि Suffix Arrays आपको उपरोक्त उत्तरों मिल सकता है। गहराई से स्पष्टीकरण में थोड़ी अधिक के लिए Suffix Trees के लिए विकिपीडिया प्रविष्टि पर भी एक नज़र डालें।
बेस्डीज जो मैं answer above से सहमत हूं कि आप शायद ऐसे प्रश्नों के लिए SQL डेटाबेस का उपयोग कर सकते हैं। डेटा के खिलाफ एक एसक्यूएल क्वेरी करना शायद प्रत्यय सरणी के बिना आप जो चाहते हैं उसे प्राप्त करने के सबसे तेज़ तरीकों में से एक है।
एसक्यूएल किए बिना चीजों को गति देने की एक चीज़ पहले नाम, मध्यनाम, अंतिम नाम को एक लोअरकेस स्ट्रिंग में रखना होगा, और उसे एक नए मानचित्र में डालना होगा जो ऐरे इंडेक्स का संदर्भ दे रहा है। इस तरह आप हर समय लोअरकेस करने के बिना हैशप के केवल 10.000 तारों को खोज को कम कर सकते हैं। यह थोड़ा तेज हो सकता है लेकिन निश्चित रूप से अधिक स्मृति की आवश्यकता है। शायद मेलिंग को तेज करने के लिए नियमित अभिव्यक्तियों के साथ कुछ करने का प्रयास करें।
एक और विकल्प वास्तव में Lucene जैसे किसी खोज के साथ सर्चइंडेक्स बनाना होगा, भले ही मुझे लगता है कि यह वास्तव में एंड्रॉइड डिवाइस पर अधिक होगा, लेकिन सादे जावा में काम कर सकता है और लुसीन में इंफिक्स खोज सुपर उच्च प्रदर्शन नहीं है।

+0

क्या SQLite (या अन्य SQL DBMS) वास्तव में infix खोज के साथ मदद करेगा? क्या इसके लिए विशेष प्रकार की अनुक्रमणिका है? जहां तक ​​मुझे पता है, मानक एसक्यूएल इंडेक्स को तेजी से इन्फिक्स (शामिल) खोज करने के लिए डिज़ाइन नहीं किया गया है। – WildWezyr

+0

वैसे यह निश्चित रूप से सबसे तेज़ तरीका नहीं होगा, उचित पूर्ण टेक्स्ट इंडेक्स का उपयोग करना तेज़ होगा। लेकिन मेरा मानना ​​है कि एसक्यूएल लाइट में क्वेरी करना सरणी – AGrunewald

+0

के माध्यम से खोज से तेज़ है 1) AFAIK पूर्ण पाठ खोज समाधान (लुसीन इत्यादि) को इंफिक्स खोजों को तेज़ करने के लिए डिज़ाइन नहीं किया गया है। यदि आप जानते हैं कि वे हैं, तो कृपया इसके बारे में आलेख/दस्तावेज़ीकरण अध्याय को लिंक दें। 2) आपकी धारणा के आधार पर क्या विश्वास है? यहां तक ​​कि एसक्यूएल इंजन को सभी वस्तुओं (रिकॉर्ड्स) के माध्यम से फिर से शुरू करना होगा जैसे सरणी सूची में सभी वस्तुओं के माध्यम से पुनरावृत्ति करना होगा। यह इन्फिक्स खोज में शामिल होने के कारण है, अगर यह सरल प्रकार की खोज (उपसर्ग खोज, सटीक मूल्य खोज इत्यादि) होगी - सूचकांक का उपयोग करके एसक्यूएल पर गंभीर लाभ होगा। – WildWezyr

-1

आरंभ में आप 10,000+ सूची कैसे पुनर्प्राप्त कर रहे हैं? यदि आप केवल instance of SQLite का उपयोग कर रहे हैं, तो मैं वास्तव में, दृढ़ता से अनुशंसा करता हूं कि आप इसे SQL में करें।

+0

क्या SQLite (या अन्य SQL DBMS) वास्तव में infix खोज के साथ मदद करेगा? क्या इसके लिए विशेष प्रकार की अनुक्रमणिका है? जहां तक ​​मुझे पता है, मानक एसक्यूएल इंडेक्स को तेजी से इन्फिक्स (शामिल) खोज करने के लिए डिज़ाइन नहीं किया गया है। – WildWezyr

0

बहुत देर से उत्तर हो सकता है लेकिन यह अन्य समस्याओं के लिए एक ही समस्या में फंसने में मदद करता है।

Java 8 (2014) कोड की एक पंक्ति में इस समस्या को नदियों और lambdas का उपयोग कर हल करती है:

Stream Api का उपयोग करके आप पाश और अधिक सुविधा के लिए उपलब्ध हैं के लिए बिना डेटा फ़िल्टर कर सकते हैं।

List<MyObject> mFilteredMyObjectList = mMyObjectList.stream() 
    .filter(d -> d.getFirstName().toString().toLowerCase().indexOf(sv) >= 0 
    || d.getMiddleName().toString().toLowerCase().indexOf(sv) >= 0 
    || d.getLastName().toString().toLowerCase().indexOf(sv) >= 0).collect(Collectors.toList()); 

अधिक जानकारी के लिए लिंक नीचे देखें,

Link1 Link2