「解決方法」是一個可怕的想法。這是效率低下的(使用更多的Math.random()
而不是必要的),正如你所說的,對於一些排序算法是很危險的。這也是有偏見的(至少對於我的nodeJS安裝中的sort()
版本,儘管我無法解釋爲什麼)。這裏的分選陣列[1, 2, 3]
60000倍和計數多少每個排列的典型結果顯示了:
[1,2,3]:14821倍
[1,3,2]:7637倍
[2,1,3]:15097倍
[2,3,1]:7590倍
[3,1,2]:7416倍
[3,2,1]:7439倍
對於無偏差洗牌,六個排列應該出現eq平均而言常常是6萬次重複的約10000次。在我的實驗中,[1,2,3]和[2,1,3]出現的頻率大約是其他四種排列的兩倍。這在測試的許多次運行中都是一致的。
你好得多粘到標準費雪耶茨洗牌(在網絡上的this Wikipedia article和其他許多地方所描述的)。在僞代碼,它看起來像這樣(從維基百科的文章取):
-- To shuffle an array a of n elements (indices 0..n-1):
for i from n−1 downto 1 do
j ← random integer such that 0 ≤ j ≤ i
exchange a[j] and a[i]
不要太複雜,絕對是一個更好的辦法。這是我的JavaScript版本(可能會清理一下):
function shuffleFisherYates(a) {
var i, j, tmp;
for (i = a.length - 1; i > 0; --i) {
j = Math.floor(Math.random() * (i + 1));
tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
return a;
}
P.S.作爲參考,這裏是我用來測試你的解決方法的代碼:
function shuffleRandomSort(a) {
a.sort(function() { return 0.5 - Math.random() });
return a;
}
function score(scores, result) {
var index;
if (result[0] === 1) {
index = result[1] === 2
? 0 // [1, 2, 3]
: 1; // [1, 3, 2]
} else if (result[0] === 2) {
index = result[1] === 1
? 2 // [2, 1, 3]
: 3; // [2, 3, 1]
} else { // result[0] === 3
index = result[1] === 1
? 4 // [3, 1, 2]
: 5; // [3, 2, 1]
}
scores[index]++;
}
function runTest(shuffler, n) {
var scores = [0, 0, 0, 0, 0, 0],
a;
for (var i = 0; i < n; ++i) {
a = [1, 2, 3];
score(scores, shuffler(a));
}
console.log(scores);
}
console.log(shuffleRandomSort, runTest(60000));
與ES6相同的Fisher-Yates shuffle算法要慢得多:/ – BrunoLM
是的,1和3都是Fisher-Yates。由於結構化的分配(我猜在大多數瀏覽器中沒有很好的優化),版本3可能會比較慢。與手動編碼的循環相比,我很驚訝lodash shuffle的表現很差。那可能是因爲你的測試缺乏熱身循環? –