本文實例講述了javascript實現數組內值索引隨機化及創建隨機數組的方法。分享給大家供大家參考。具體如下:
今天在QW交流群裡看到有同學討論使數組隨機化的問題,其中給出的算法很不錯,讓我想起了之前自己實現過的不怎麼“漂亮”的方法。想想我們有時候在繁忙的寫業務代碼時只是為了實現其功能,並未花太大心思去思考是否有更好的實現方法。
就這個數組問題(隨即排序一個數組裡的值,返回一個新數組)來說,我以前的實現方法是這樣的:
function randArr(arr) { var ret = [], obj = {}, i = arr.length, l = i, n; while (--i >= 0) { n = Math.floor( Math.random() * l ); if (obj[n] === void 0) { ret[ret.length] = obj[n] = arr[n]; } else { i++; } } return ret; }
上面的代碼會工作,但並不是一個好的算法,它打算執行“原數組的長度”次循環,每一次循環會隨機取一個原數組中的索引,然後判斷該索引是否已被取過,如果沒有則把該索引的值放入新數組中,如果取過則把自減鍵 i 自增1(目的是重復該次循環直到取到另一個未取過的索引)。這樣的方法的性能是很看人品的,原因相信看到這種思路的同學都已明白了。
現在給出群裡那位同學的算法:
function randArr(arr) { var ret = [], i = arr.length, n; arr = arr.slice(0); while (--i >= 0) { n = Math.floor( Math.random() * i); ret[ret.length] = arr.splice(n, 1)[0]; } return ret; }
這是一個相當巧妙的算法,在每次循環中取一個隨機的索引後,並把它的值從數組中刪除,這樣,如果後面依然隨機取到這個索引,這個索引就已經不再是上一次取到的值了,而且隨機數的取值范圍會根據數組的長度的減小而減小,這樣就能一次性循環一定的次數而得到理想的結果。
還看到了一個改進版的,是考慮到了對數組的刪除操作而導致的些許性能問題,運用了JK大的洗牌算法,即把每一次刪除操作改為了位置替換操作(取到的該索引的值和當前自減鍵 i 對應的值進行互換),這樣對整個數組的影響是最小的,還是放代碼吧:
function randArr(arr) { var ret = [], i = arr.length, n; arr = arr.slice(0); while (--i >= 0) { n = Math.floor( Math.random() * i); ret[ret.length] = arr[n]; arr[n] = arr[i]; } return ret; }
最後給出一個“創建值為min~max間的隨機數組”的方法,算法原理同上面的差不多:
function makeRandArr(min, max) { var ret = [], obj = {}, n; for (; max >= min; max--) { n = Math.ceil( Math.random() * (max - min) ) + min; ret[ret.length] = obj[n] || n; obj[n] = obj[max] || max; } return ret; }
希望本文所述對大家的javascript程序設計有所幫助。