2010-01-21 33 views
5

Tôi có một dãy tên phố được sắp xếp theo thứ tự bảng chữ cái mà tôi đã thu thập từ một dịch vụ web. Mảng này tồn tại ở phía máy chủ.Trong PHP, cách nhanh chóng để tìm kiếm một mảng cho các giá trị chứa chuỗi con là gì?

Ở phía máy khách, người dùng bắt đầu nhập tên đường phố mà anh ấy sinh sống và AJAX được sử dụng để trả về danh sách kết quả trùng khớp gần nhất với tên đường phố, cộng với 9 tên đường phố tiếp theo trong mảng danh sách được cập nhật khi anh ấy đang gõ).

Ví dụ, nếu người dùng gõ "al", tôi mong chờ kết quả là một cái gì đó như sau:

  • Albany Hwy
  • Albens Vale
  • Alcaston Rd
  • Alex Gỗ Dr
  • Alice Rd
  • Allawah Ct
  • Allen Rd
  • Alloway Pl
  • Allwood Av
  • Alola St
  • Amanda Dr

Đây là thử của tôi lúc đó:

$matches = array(); 
for($i = 0; $i < count($streetNames); $i++) 
{ 
    if((stripos($streetNames, $input) === 0 && count($matches) == 0) || count($matches) < 10){ 
    $matches[] = $streetNames[$i]; 
    } else { 
    break; 
    } 
} 

Có ai khác biết một cách nhanh hơn?

Xin lưu ý: Tôi không có quyền kiểm soát cách danh sách này được lấy từ cơ sở dữ liệu - đó là từ một dịch vụ web bên ngoài.

+0

Vâng, để tìm ra * nhanh nhất * cách nào, bạn sẽ phải chuẩn nó để chắc chắn. Nhưng nếu điều này là từ một dịch vụ web bên ngoài, tôi muốn nói việc xây dựng kết nối với webservice sẽ chậm hơn bất kỳ mã nào bạn nhận được để có câu trả lời. – Gordon

+0

Vâng, tôi đã nhận được xung quanh đó bằng cách bộ nhớ đệm dữ liệu trả về từ máy chủ web trong 24 giờ. Các tên đường phố trong đô thị của chúng ta thường không thay đổi nhiều - nhưng có rất nhiều sự phát triển và các đường phố mới xuất hiện mọi lúc nên 24 giờ có vẻ như một lượng thời gian tốt. –

Trả lời

4

Cách duy nhất để nhanh hơn xem qua tất cả các chuỗi sẽ là có cấu trúc dữ liệu được tối ưu hóa cho loại điều này, một trie. Bạn có thể không có quyền kiểm soát những gì webservice cung cấp cho bạn, nhưng nếu bạn có thể cache kết quả trên máy chủ của bạn và sử dụng lại nó để phục vụ nhiều yêu cầu, thì hãy xây dựng một trie và sử dụng nó sẽ nhanh hơn nhiều.

+0

Thú vị, bởi vì tôi thực sự đang lưu trữ dữ liệu từ máy chủ web. Tôi chắc chắn sẽ xem xét điều này :) –

+0

Mate, phản ứng huyền thoại! Tìm thấy một nguồn tài nguyên php rất tốt: http://phpir.com/tries-and-wildcards –

4

Tôi nghĩ rằng những gì bạn đang tìm kiếm là preg_grep()

Bạn có thể tìm kiếm hoặc cho các yếu tố bắt đầu với các văn bản đầu vào:

$result = preg_grep('/^$input/', $streetNames); 

hoặc cho các yếu tố có chứa các văn bản ở bất kỳ nơi:

$result = preg_grep('/$input/', $streetNames); 

hoặc bạn cũng có thể neo tìm kiếm vào cuối nhưng trông không hữu ích như vậy

+0

Cảm ơn bạn đã trả lời, tôi chưa bao giờ nghe nói về preg_grep. Trong khi tôi sẽ không sử dụng nó trong trường hợp này nó trông thực sự tiện dụng và tôi sẽ nộp nó đi cho sau này :) –

5

Sử dụng preg_grep():

$matches = preg_grep('/al/', $streetNames); 

Lưu ý: phương pháp này như của bạn sẽ là một tìm kiếm brute force. Nếu bạn đang tìm kiếm một danh sách lớn các tên (hàng trăm nghìn) hoặc tìm kiếm một số lượng lớn thời gian thì bạn có thể cần một cái gì đó tốt hơn. Tuy nhiên, đối với các tập dữ liệu nhỏ thì điều này là tốt.

+0

Cảm ơn cletus. Trong khi tôi sẽ không sử dụng phương pháp này trong trường hợp cụ thể này, bạn đã mở mắt của tôi đến một chức năng tôi nếu không luôn luôn bị bỏ qua. Tôi chắc chắn sẽ sử dụng nó ở đâu đó. Cảm ơn một lần nữa :) –

+0

Điều này sẽ không bao giờ là một cách nhanh chóng: | – s3v3n

4

Không thể thực sự biết nó có nhanh hơn không, nhưng đây là phiên bản của tôi.

$input = 'al'; 
$matches = array_filter($streetNames, create_function('$v','return (stripos($v,'.$input.') !== false ? true : false);')); 
$weight = array_map(create_function('$v','return array($v,levenshtein('.$input.',$v));'),$matches); 
uasort($weight, create_function('$a,$b', 'if ($a[1] == $b[1]) {return 0;} return ($a[1] < $b[1]) ? -1 : 1;')); 
$weight = array_slice($weight, 0, 10); 

Điều này tạo danh sách trọng số kết quả phù hợp. Chúng được sắp xếp theo khoảng cách giữa chuỗi đầu vào và tên đường phố. 0 đại diện cho một sự trùng khớp thực sự.

Kết quả mảng trông như thế này

array (
    0 => 
    array (
    0 => 'Alola St', 
    1 => 7, 
), 
    1 => 
    array (
    0 => 'Allen Rd', 
    1 => 7, 
) 
) 

đâu 0 => tên đường phố và 1 => khoảng cách levenshtein

+0

Xin chào, công việc tuyệt vời Tôi thích hệ thống trọng số của bạn :) –

+0

Với tôi, tính năng tự động hoàn tất không hoàn chỉnh nếu không có trọng số như vậy hoặc bất cứ điều gì bạn muốn gọi nó. Nhưng tất nhiên đó không phải là cách duy nhất để làm điều đó. Chỉ cần một bằng chứng nhanh về khái niệm. –

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