2010-01-26 35 views
10

我正在開發Android應用程序(Android 1.6),但這可能是一個更一般的Java問題。高效過濾Java/Android中的ArrayList

我有大約10,000個對象

的ArrayList對象包含3串(名字,中間名,姓氏)。

用戶在android上顯示一個「搜索框」,他們可以通過輸入部分名稱來搜索特定的「對象」。

我有一個類(我稱之爲Filterer),它通過10,000的列表搜索匹配對象,然後將它們作爲「子列表」返回。

搜索有點慢(特別是在Android手機上),我確定我沒有以最有效的方式進行搜索/過濾。

有沒有人有關於如何加快我的搜索的建議?我的代碼如下。一種可能性是針對已經具有小寫和連接的每個信息的輔助「masterList」進行搜索...但是可能有其他方式來改善這種搜索,這也將有所幫助。

TIA !!

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- contains-string是用C++記住的,但是一般的解決方案(數據結構和算法)是獨立於語言的。 – WildWezyr

回答

6

是的,這是肯定的痛苦爲每個循環迭代小寫幾個對象(加上可能冗餘toString?),並且還不好的做法,呼籲list.size()每次迭代—該值應在循環之前被緩存開始。

無論如何,如果你使用這麼多的數據,是否有一個原因,你沒有使用SQLite數據庫來存儲和顯示/過濾你的列表使用CursorAdapter

這將是推薦的方式來實現這種規模的東西。

+0

SQLite(或其他SQL DBMS)真的可以幫助中綴搜索嗎?它有什麼特殊的索引? – WildWezyr

+1

本地循環「大小」變量是一個Java老婆婆故事,就像聲明方法「最終」一樣。 JVM將內聯size()調用,您將看不到性能提升。 –

+3

@ Civil不聽話:大多數JVM都是如此,但Android設備上的Dalvik虛擬機並非如此。有關更多信息,請參閱http://developer.android.com/intl/fr/guide/practices/design/performance.html#cache_fields。 –

2

也許你可以交易一些空間的速度?爲您的數據創建某種形式的索引?

例如:

  1. 創建爲每個字符(A-Z)與所有 「myObject的」 S其中名稱的一部分包含字符的清單(注意特殊字符!)。對於每個條目計數「MyObject」的數量
  2. 如果用戶在查詢中輸入內容,請查找單個字符並僅搜索最少量條目的列表。

當然,添加一個名稱會要求您將其添加到索引。

0

經過研究多一點我發現Suffix Arrays可以讓你的禁食答案。請查看Suffix Trees的維基百科條目,以獲得更深入的解釋。
我同意answer above,你可以使用SQL數據庫進行這樣的查詢。對數據做一個Sql查詢可能是最快速的方法之一,無需後綴數組即可獲得你想要的內容。
有一件事情,加快了一點,而不做SQL是將firstName,middleName,lastName放入一個小寫字符串,並將其放入一個新的引用Array索引的Map中。通過這種方式,您可以將搜索量減少到只有10.000個散列映射的字符串,而無需每次都進行小寫操作。它可能會更快,但當然需要更多的內存。也許嘗試用正則表達式來加快匹配。
另一種選擇是真正創建一個類似於Lucene的searchindex,儘管我認爲這對於Android設備來說確實是過火,但是可以在普通Java中工作,而Lucene中的中綴搜索也不是超高性能。

+0

SQLite(或其他SQL DBMS)真的可以幫助中綴搜索嗎?它有什麼特殊的索引?據我所知,標準的SQL索引並不是用來做快速的中綴(包含)搜索。 – WildWezyr

+0

那麼它絕對不是最快的方式,使用適當的全文索引會更快。但我相信在SQL Lite中執行查詢比通過數組搜索更快 – AGrunewald

+0

1)AFAIK全文搜索解決方案(Lucene等)不是用來加速中綴搜索的。如果你知道它們,請給出有關該文章/文檔章節的鏈接。 2)你的信念是基於什麼?即使SQL引擎也必須遍歷所有項目(記錄),就像迭代ArrayList中的所有項目一樣。這是因爲涉及中綴搜索,如果它是更簡單的搜索類型(前綴搜索,精確值搜索等) - 使用索引會導致SQL的嚴重增益。 – WildWezyr

-1

你最初如何檢索10,000+列表?如果你只是使用instance of SQLite,我真的會,強烈建議你在SQL中這樣做。

+0

SQLite(或其他SQL DBMS)真的可以幫助中綴搜索嗎?它有什麼特殊的索引?據我所知,標準的SQL索引並不是用來做快速的中綴(包含)搜索。 – WildWezyr

0

可能已經太遲了,但它對其他人的幫助仍存在相同的問題。

Java 8 (2014)解決了使用流和lambda表達式這個問題的一行代碼:

使用Stream Api可以不用for循環和功能更是可用的過濾數據。

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