2013-02-03 59 views
24

通過從400X通過開關a.localeCompare(b)至(一個<b?-1:(a> b?1:0)排序加速比)

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

切換一個JavaScript排序功能

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

我能夠以減少在Chrome中將~1700元素陣列從1993毫秒排序到5毫秒的時間。幾乎是400倍的加速。不幸的是,這是以正確排列非英文字符串爲代價的。

很顯然,當我嘗試進行排序時,我無法將UI阻塞2秒。有什麼我可以做,以避免可怕的慢localeCompare但仍然支持本地化的字符串?

+1

考慮讓一個網絡工作者異步執行基於'localeCompare'的排序。您可能會發現,對這些數據進行序列化和反序列化所花費的時間超過了異步執行的好處,但值得一試。 –

+0

這可能會工作,但2秒仍然很慢,以顯示結果。 –

+0

你可以考慮一種不同的方法 - 比如讓列表從頭開始排序,所以你永遠不需要明確地排序它。數據來自哪裏? JavaScript已經實現了一些自我排序的數據結構:http://stackoverflow.com/a/5309821/139010或http://stackoverflow.com/a/3809836/139010 –

回答

5

很難知道最快的排序而沒有看到您正在排序的數據。但jsperf有很多很好的測試結果,顯示排序類型之間的性能差異: http://jsperf.com/javascript-sort/45 http://jsperf.com/sort-algorithms/31

但是這些都不考慮本地化字符串,我想像有沒有簡單的方法來本地化字符串和localeCompare是排序可能是最好的解決方案。

查看mozilla參考說: 「比較大數量的字符串時,比如在排序大數組時,最好創建一個Intl.Collat​​or對象並使用它的compare屬性提供的函數。」 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare

但要去Intl.Collat​​or引用它表明沒有爲Firefox/Safari https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Collator

支持,你可以嘗試使用一些對localCompare的選項,以加快性能。不過,我剛剛做了一個快速測試改變靈敏度水平,現在看來似乎不會提高性能:

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

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

+0

>>最好創建一個Intl.Collat​​or對象並使用它的compare屬性提供的函數 - 絕對同意。我做了一些測量,是的,比較速度要高得多16ms對於1000行上的localCompare而言,25sec與012比較 – Serge

-2

我不知道你還在尋找解決這個問題

// 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; 
}); 

我添加了一個=== 1檢查你的代碼,這提高了400倍PERF這意味着兩者具有可比性PERF號碼。

逆足數與localeCompare ARR尺寸:3200 平均時間參加了10次:60毫秒

逆足數與>辦法。平均花費55毫秒

+0

我不確定這是如何解決這個問題的。你可以用你的發現做一個jsperf嗎? === 1如何提高perf 400x。 –

+3

Sry,但你的解決方案是**錯誤**:'localeCompare()'可能會返回不同於-1,0或1的值。查看[doc](http://developer.mozilla.org/en-US /文檔/網絡/的JavaScript /參考/ Global_Objects /字符串/ localeCompare)。另外,我高度懷疑添加乘法比沒有乘法要快。您應該製作2個比較器:一個用於升序,一個用於降序。 JIT將能夠更好地內聯他們。 – jlgrall

9

我處理/大部分/拉丁字符時發現的一種有效方法是在兩個字符串匹配特定正則表達式時使用運算符。 EG:/^[\w-.\s,]*$/

如果兩個字符串都匹配表達式,速度會更快,而在最壞的情況下,它比盲目調用localeCompare要慢得多。

這裏舉例:http://jsperf.com/operator-vs-localecompage/11

+0

絕對完美的我,並值得更多upvotes!我的數據集是99%的無焦點,所以你的no_locale正則表達式有很大的不同。 – Codemonkey

+0

你能解釋一下正則表達式的作用嗎? –

+0

正則表達式檢測字符串是否只包含字母數字字符。 \ w匹配包括下劃線在內的任何字母數字字符。相當於[A-Za-z0-9_]。 LocaleCompare與這些字符無關(在大多數情況下?) –

1

嘗試在2個步驟排序是:

  1. 與運營商:如你所說,這將是更快
  2. 然後用localCompare() 400倍:這已經少比較要做,因爲數組大多數是排序的。

注意:我認爲localCompare()將主要被稱爲至少有一個不是英語的字符串。因此,撥打localCompare()與2個英文字符串的電話數量應大大減少。

下面是代碼:

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

該方案具有短且易於使用的優點。如果數組主要包含英文字符串,那麼這將很有效。你有更多的非英語字符串,第一類將是不太有用的。但是,由於添加腳本很容易,因此很容易看出這種方法是否值得。

現在如果我是你,我也會使用Intl.Collator,因爲當你有很多比較要做時,它被認爲比localCompare()快得多。

+2

不是每種排序算法都可以利用已經大多數排序的數組(有趣的是,對於非常天真的快速排序來說這是一場災難)。不知道如果那些在JavaScript中使用可以。 – maaartinus

相關問題