2013-02-03 44 views
24

Bằng cách chuyển một chức năng sắp xếp javascript từ400x Sorting Speedup bởi Switching a.localeCompare (b) (a <b?-1:(a> b 1: 0))

myArray.sort(function (a, b) { 
    return a.name.localeCompare(b.name); 
}); 

để

myArray.sort(function (a, b) { 
    return (a.name < b.name ? -1 : (a.name > b.name ? 1 : 0)); 
}); 

tôi đã có thể để giảm thời gian sắp xếp mảng phần tử ~ 1700 trong Chrome từ 1993 mili giây đến 5 mili giây. Tốc độ tăng lên gần 400 lần. Thật không may, điều này là do chi phí phân loại chính xác các chuỗi không phải tiếng Anh.

Rõ ràng là tôi không thể chặn giao diện người dùng của mình trong 2 giây khi tôi cố gắng sắp xếp. Có bất cứ điều gì tôi có thể làm để tránh locale chậm khủng khiếpCompare nhưng vẫn duy trì hỗ trợ cho các chuỗi địa phương?

+1

Cân nhắc quay vòng một công nhân web để thực hiện sắp xếp dựa trên 'localeCompare' không đồng bộ. Bạn có thể thấy rằng thời gian dành cho việc tuần tự hóa và deserializing số lượng dữ liệu đó vượt quá những lợi ích của việc làm nó không đồng bộ, nhưng nó đáng để quay. –

+0

Điều đó có thể hoạt động nhưng 2 giây vẫn thực sự chậm để hiển thị kết quả. –

+0

Bạn có thể xem xét một cách tiếp cận khác - như giữ danh sách được sắp xếp ngay từ đầu, vì vậy bạn không bao giờ cần phải sắp xếp nó một cách rõ ràng. dữ liệu đến từ đâu????? Có một số cấu trúc dữ liệu tự sắp xếp cho JavaScript đã được triển khai: http://stackoverflow.com/a/5309821/139010 hoặc http://stackoverflow.com/a/3809836/139010 –

Trả lời

5

Rất khó để biết sắp xếp nhanh nhất mà không thấy dữ liệu bạn sắp xếp. Nhưng jsperf có rất nhiều bài kiểm tra tốt cho thấy sự khác biệt hiệu suất giữa các loại phân loại: http://jsperf.com/javascript-sort/45 http://jsperf.com/sort-algorithms/31

Tuy nhiên không ai trong số những tài khoản cho các chuỗi cục bộ, và tôi muốn tưởng tượng không có cách nào dễ dàng để sắp xếp chuỗi cục bộ và localeCompare là có lẽ là giải pháp tốt nhất cho việc này.

Nhìn vào tham chiếu mozilla là: "Khi so sánh số lượng lớn chuỗi, chẳng hạn như sắp xếp mảng lớn, tốt hơn là tạo đối tượng Intl.Collator và sử dụng hàm do thuộc tính so sánh của nó cung cấp." https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare

Nhưng đi đến Intl.Collator tham khảo nó cho thấy rằng không được hỗ trợ cho firefox/safari https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Collator

bạn có thể thử sử dụng một số các tùy chọn trên localCompare để tăng tốc độ hiệu suất. Nhưng tôi vừa thực hiện một thử nghiệm nhanh thay đổi mức độ nhạy cảm và nó có vẻ như nó sẽ không cải thiện hiệu suất:

list.sort(function(a, b) { 
    return a.localeCompare(b, {sensitivity:'base'}); 
}); 

http://jsperf.com/sort-locale-strings

+0

>> nó là tốt hơn để tạo ra một đối tượng Intl.Collator và sử dụng hàm được cung cấp bởi thuộc tính so sánh của nó - hoàn toàn đồng ý. Tôi đã thực hiện một số phép đo và có, tốc độ so sánh cao hơn nhiều 16ms so với 25 giây với localCompare trên 1000 hàng – Serge

-2

Tôi không biết bạn vẫn đang tìm kiếm giải pháp cho vấn đề này

// Defaulted to ascending 
// 1 asc | -1 desc 
var direction = 1; 
myArray.sort(function (a, b) { 
    return a.name.localeCompare(b.name) === 1 ? direction : -1 * direction; 
}); 

tôi đã thêm một tấm séc === 1 mã của bạn và điều này được cải thiện về hiệu suất 400x đó có nghĩa là cả hai đều có số perf thể so sánh được.

số Perf với kích thước arr localeCompare: 3200 Avg thời gian mất trong 10 lần lặp lại: 60 ms

số Perf với> cách tiếp cận. Thời gian trung bình mất 55 ms

+0

Tôi không chắc chắn cách giải quyết vấn đề này. Bạn có thể làm một jsperf với phát hiện của bạn? làm thế nào để === 1 cải thiện perf 400x. –

+3

Sry, nhưng giải pháp của bạn là ** WRONG **: 'localeCompare()' có thể trả về các giá trị khác -1, 0 hoặc 1. Nhìn vào [doc] (http://developer.mozilla.org/en-US/docs/Web/JavaScript/Tham chiếu/Global_Objects/String/localeCompare). Ngoài ra, tôi rất nghi ngờ rằng việc thêm một phép nhân nhanh hơn là không có. Bạn nên thực hiện 2 bộ so sánh: một cho tăng dần, một cho thứ tự giảm dần. JIT sẽ có thể nội tuyến chúng tốt hơn nhiều. – jlgrall

9

Phương pháp tiếp cận hiệu quả mà tôi tìm thấy khi giao dịch với/chủ yếu/ký tự latin là sử dụng toán tử bất cứ khi nào cả hai chuỗi khớp với một regex cụ thể. EG: /^[\w-.\s,]*$/

Sẽ nhanh hơn nếu cả hai chuỗi khớp với biểu thức và tệ nhất là có vẻ chậm hơn một chút so với ngôn ngữ gọi là localeCompare.

Ví dụ ở đây: http://jsperf.com/operator-vs-localecompage/11

+0

Hoàn toàn hoàn hảo đối với tôi, và xứng đáng được nhiều người vượt trội hơn! Tập dữ liệu của tôi không có giá trị 99%, do đó, regex no_locale của bạn tạo ra sự khác biệt lớn. – Codemonkey

+0

Bạn có thể giải thích những gì regex không? –

+0

Regex phát hiện chuỗi có chứa các ký tự chữ và số hay không. \ w Kết hợp bất kỳ ký tự chữ và số nào bao gồm dấu gạch dưới. Tương đương với [A-Za-z0-9_]. LocaleCompare không liên quan đến các ký tự này (trong hầu hết các trường hợp?) –

1

Hãy thử sắp xếp nó theo 2 bước:

  1. Với các nhà điều hành: như bạn nói, nó sẽ nhanh hơn
  2. Sau đó, với localCompare() 400 lần: đây có bây giờ ít so sánh để làm vì mảng chủ yếu được sắp xếp.

Lưu ý: Tôi nghĩ rằng localCompare() chủ yếu sẽ được gọi với ít nhất 1 chuỗi không phải là tiếng Anh. Vì vậy, số lượng các cuộc gọi đến localCompare() với 2 chuỗi tiếng Anh nên được giảm đáng kể.

Đây là mã:

myArray.sort(function(a, b) { 
    return (a.name < b.name ? -1 : (a.name > b.name ? 1 : 0)); 
}); 

myArray.sort(function(a, b) { 
    return a.name.localeCompare(b.name); 
}); 

Giải pháp này có ưu điểm là ngắn và dễ sử dụng. Nó sẽ hiệu quả nếu mảng chứa hầu hết các chuỗi tiếng Anh. Bạn không có nhiều chuỗi tiếng Anh, loại đầu tiên sẽ ít hữu ích hơn. Nhưng vì nó rất dễ dàng để thêm vào các kịch bản của bạn, nó cũng dễ dàng để xem nếu phương pháp này là đáng giá.

Bây giờ nếu tôi là bạn, tôi cũng sẽ sử dụng một số Intl.Collator, vì nó được cho là nhanh hơn nhiều so với localCompare() khi bạn có nhiều so sánh để thực hiện.

+2

Không phải mọi thuật toán sắp xếp đều có thể tận dụng một mảng đã được sắp xếp chủ yếu (đủ thú vị, cho một quicksort rất ngây thơ đó là một thảm họa). Không có ý tưởng nếu những người sử dụng trong Javascript có thể. – maaartinus

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