2010-01-26 35 views
10

Tôi đang phát triển một ứng dụng Android (Android 1.6), nhưng đây có lẽ là một câu hỏi Java tổng quát hơn.Lọc một ArrayList hiệu quả trong Java/Android

Tôi có một ArrayList khoảng 10.000 đối tượng

đối tượng chứa 3 chuỗi (firstName, middleName, lastName).

Người dùng được hiển thị với "hộp tìm kiếm" trên Android nơi họ có thể tìm kiếm "đối tượng" cụ thể bằng cách nhập một phần tên.

Tôi có một lớp (mà tôi gọi là Bộ lọc) tìm kiếm trong danh sách 10.000 đối tượng phù hợp và sau đó trả về chúng dưới dạng "danh sách phụ".

Tìm kiếm là một chút SLOW (đặc biệt là trên điện thoại Android) và tôi chắc chắn tôi không thực hiện tìm kiếm/lọc theo cách hiệu quả nhất có thể.

Có ai có bất kỳ đề xuất nào về cách tăng tốc độ tìm kiếm của tôi không? Mã của tôi là dưới đây. Một khả năng để tìm kiếm dựa trên "masterList" phụ đã có mọi thông tin trong chữ thường và ghép nối ... nhưng có thể có thêm các cách để cải thiện tìm kiếm này cũng có thể hữu ích.

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

Nhìn vào đây để vấn đề tương tự: http://stackoverflow.com/questions/2085445/fast-index-for- contains-string nó được hỏi với C++ trong tâm trí, nhưng giải pháp chung (cấu trúc dữ liệu và thuật toán) là ngôn ngữ độc lập. – WildWezyr

Trả lời

6

Vâng, nó chắc chắn đau đớn to-chữ thường một số đối tượng cho mỗi lần lặp (cộng với một khả năng dư thừa toString?), Và cũng có thể thực hành xấu để gọi list.size() cho mỗi lần lặp — rằng giá trị nên được lưu trữ trước khi vòng lặp bắt đầu.

Dù sao, nếu bạn đang làm việc với nhiều dữ liệu này, có lý do nào bạn không sử dụng cơ sở dữ liệu SQLite để lưu trữ và hiển thị/lọc danh sách của mình bằng cách sử dụng CursorAdapter không?

Đó sẽ là cách được khuyến nghị để triển khai thứ gì đó có kích thước này.

+0

SQLite (hoặc các DBMS SQL khác) có thực sự trợ giúp với tìm kiếm infix không? Nó có loại chỉ số đặc biệt cho điều đó không? – WildWezyr

+1

Các biến "kích thước" vòng lặp cục bộ là một câu chuyện về Old Wives của Java, giống như khai báo các phương thức "final". JVM sẽ inline kích thước() gọi và bạn sẽ thấy không có lợi ích hiệu suất. –

+3

@Civil Không tuân thủ: điều này đúng với hầu hết các JVM, nhưng không nhất thiết phải đúng đối với VM Dalvik trên các thiết bị Android. Xem http://developer.android.com/intl/fr/guide/practices/design/performance.html#cache_fields để biết thêm thông tin. –

2

Có thể bạn có thể giao dịch một số không gian cho một số tốc độ? Tạo một số biểu mẫu của chỉ mục cho dữ liệu của bạn?

Ví dụ:

  1. Tạo một danh sách cho mỗi ký tự (a-z) với tất cả các "MyObject" là nơi một phần của tên chứa ký tự (được nhận thức của các nhân vật đặc biệt!). Đối với mỗi mục nhập, hãy đếm số "MyObject" s
  2. Nếu người dùng nhập truy vấn, hãy tìm các ký tự riêng lẻ và chỉ tìm kiếm danh sách có số lượng mục nhập nhỏ nhất.

Tất nhiên việc thêm tên sẽ yêu cầu bạn thêm nó vào chỉ mục.

0

Sau khi nghiên cứu thêm một chút, tôi đã nhận thấy rằng Suffix Arrays có thể giúp bạn có được câu trả lời nhanh chóng. Ngoài ra, hãy xem mục nhập Wikipedia cho Suffix Trees để biết thêm một chút về giải thích chi tiết.
Bên cạnh đó tôi đồng ý với answer above rằng bạn có thể sử dụng Cơ sở dữ liệu SQL cho các truy vấn như vậy. Làm một truy vấn Sql chống lại dữ liệu có lẽ là một trong những cách nhanh nhất để có được những gì bạn muốn mà không có mảng hậu tố.
Một điều để tăng tốc mọi thứ lên một chút mà không cần làm SQL sẽ đặt firstName, middleName, lastName vào một chuỗi ký tự chữ thường và đặt nó vào một Bản đồ mới có tham chiếu đến chỉ mục Mảng. Bằng cách đó bạn có thể giảm tìm kiếm chỉ còn 10.000 chuỗi hashmap mà không cần phải viết thường xuyên mỗi lần. Nó có thể nhanh hơn một chút nhưng tất nhiên đòi hỏi nhiều bộ nhớ hơn. Có thể cố gắng làm điều gì đó với các biểu thức thông thường để tăng tốc độ khớp.
Một tùy chọn khác sẽ thực sự tạo một searchindex với một cái gì đó như Lucene mặc dù tôi nghĩ rằng nó sẽ thực sự quá mức trên một thiết bị Android nhưng có thể làm việc trong Java đơn giản và tìm kiếm infix trong Lucene không phải là siêu hiệu suất cao hoặc.

+0

SQLite (hoặc các DBMS SQL khác) có thực sự trợ giúp với tìm kiếm infix không? Nó có loại chỉ số đặc biệt cho điều đó không? Theo như tôi biết, các chỉ mục SQL chuẩn không được thiết kế để thực hiện tìm kiếm nhanh (chứa). – WildWezyr

+0

Vâng, nó chắc chắn sẽ không phải là cách nhanh nhất, sử dụng một chỉ mục văn bản đầy đủ thích hợp sẽ nhanh hơn. Nhưng tôi tin rằng việc thực hiện truy vấn trong SQL Lite nhanh hơn tìm kiếm thông qua mảng – AGrunewald

+0

1) Các giải pháp tìm kiếm toàn văn bản AFAIK (Lucene, vv) không được thiết kế để tăng tốc tìm kiếm. Nếu bạn biết rằng họ đang có, xin vui lòng cung cấp cho liên kết đến bài viết/tài liệu chương về điều đó. 2) Niềm tin của bạn dựa trên điều gì? Ngay cả công cụ SQL phải lặp qua tất cả các mục (bản ghi) giống như lặp qua tất cả các mục trong danh sách mảng sẽ làm. Điều này là do tìm kiếm infix có liên quan, nếu nó sẽ là loại tìm kiếm đơn giản hơn (tìm kiếm tiền tố, tìm kiếm giá trị chính xác, v.v.) - sẽ có mức tăng nghiêm trọng đối với SQL bằng cách sử dụng chỉ mục. – WildWezyr

-1

Ban đầu bạn sẽ truy xuất danh sách 10.000+ như thế nào? Nếu bạn chỉ sử dụng instance of SQLite, tôi thực sự, mạnh mẽ khuyên bạn nên làm điều này trong SQL.

+0

SQLite (hoặc các DBMS SQL khác) có thực sự trợ giúp với tìm kiếm infix không? Nó có loại chỉ số đặc biệt cho điều đó không? Theo như tôi biết, các chỉ mục SQL chuẩn không được thiết kế để thực hiện tìm kiếm nhanh (chứa). – WildWezyr

0

có thể là câu trả lời quá muộn nhưng đó là trợ giúp cho người khác trong vấn đề tương tự bị mắc kẹt.

Java 8 (2014) giải quyết vấn đề này bằng con suối và lambdas trong một dòng mã:

Sử dụng Stream Api bạn có thể lọc dữ liệu mà không cho vòng lặp và tính năng hơn của có sẵn.

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()); 

Để biết thêm thông xem dưới đây liên kết,

Link1 Link2

Các vấn đề liên quan