[javascript]
function mess(arr){
var _floor = Math.floor, _random = Math.random,
len = arr.length, i, j, arri,
n = _floor(len/2)+1;
while( n-- ){
i = _floor(_random()*len);
j = _floor(_random()*len);
if( i!==j ){
arri = arr[i];
arr[i] = arr[j];
arr[j] = arri;
}
}
return arr;
}
var testa = [1, 2, 3, 4, 5, 6, 7];
mess(testa);
console.log(testa);
要注意一點的是,這是改變原數組的,不想改變原數組的話請先拷貝原數組:
[javascript]
var testa = [1, 2, 3, 4, 5, 6, 7];
var newarr = mess( testa.slice(0) ); //這裡只是淺拷貝數組
console.log(testa);
console.log(newarr);
這個洗牌函數算好嗎?
呵呵,或許經過測試你會發現:有一些元素在洗完牌後位置依然是原來的位置,而且出現這種元素的幾率很大。那怎麼改進呢?
在現實當中,我們洗完牌後,通常還會把撲克一分為二(俗稱“切牌”),然後交換這兩部分的上下位置。嗯,對,這個洗牌函數裡我們沒有切牌!
所以我們可以做如下改進:
[javascript]
//洗牌演算法
function mess(arr){
var _floor = Math.floor, _random = Math.random,
len = arr.length, i, j, arri,
n = _floor(len/2)+1;
while( n-- ){
i = _floor(_random()*len);
j = _floor(_random()*len);
if( i!==j ){
arri = arr[i];
arr[i] = arr[j];
arr[j] = arri;
}
}
//增加切牌操作
i = _floor(_random()*len);
arr.push.apply(arr, arr.splice(0,i));
//return arr; //要不要返回打亂後的數組呢?
}
var testa = [1, 2, 3, 4, 5, 6, 7, 8, 9];
var newarr = testa.slice(0);
mess(newarr);
console.log(testa);
console.log(newarr);
好,現在看來,已經很少出現洗牌前後位置不變的元素了,可以說大功告成了。
巴特,稍等,我們已經發現,這個洗牌函數是會改變原始數組的,那麼,接下來有一個問題:這個函數要不要傳回值,返回打亂後的數組?因為我可能想這麼來調用它:
[javascript]
var testa = [1, 2, 3, 4, 5, 6, 7];
var newarr = mess( testa.slice(0) ); //這裡只是淺拷貝數組
這種調用方式好嗎?如果加上這種調用方式,那麼可以算一共有兩種調用方式。
其實,對這麼一個簡單函數而言,調用方法應該越簡單越好,簡單易用,最好只提供一種調用方式。使用方法多了就需要人多記東西,容易讓人迷糊。所以,我不想給這個洗牌函數傳回值,不想提供這種調用方式。
而且還有一個原因:這有利於強調這是一個改變原數組的函數,而不是通過傳回值來給出調用結果,這樣可以讓調用者明確知道調用函數的影響。