背景 今天打开博客页面,发现主页这么呈现:
很明显是因为随机封面算法是真随机,于是找到现在在用的主题butterfly中,随机封面的算法如下:
1 2 3 4 5 6 7 8 9 const randomCoverFn = ( ) => { const { cover : { default_cover : defaultCover }, } = hexo.theme .config ; if (!defaultCover) return false ; if (!Array .isArray (defaultCover)) return defaultCover; const num = Math .floor (Math .random () * defaultCover.length ); return defaultCover[num]; };
强迫症简直不能忍,于是立马写一个shuffle函数
闭包+克隆数组的写法 这是想到的最简单的一个办法,写法也简单:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 const defaultCover = ["1" , "2" , "3" , "4" , "5" ];const randomCoverFn = (() => { if (!defaultCover) return false ; if (!Array .isArray (defaultCover)) return defaultCover; const shuffle = [...defaultCover]; let lastChoice = null ; return function ( ) { if (shuffle.length < 2 ) { shuffle.push (...defaultCover); } let num; do { num = Math .floor (Math .random () * shuffle.length ); } while (shuffle[num] === lastChoice); let res = shuffle.splice (num, 1 )[0 ]; lastChoice = res; return res; }; })(); let last = null ;for (let i = 0 ; i < 1000 ; i++) { let s = randomCoverFn (); if (last === s) { console .log ("error !" ); } last = s; }
这个办法问题多多:
不够优雅 都记录上次选择了,何必辛苦克隆数组 于是优化版本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 const defaultCover = ["1" , "2" , "3" , "4" , "5" ];const randomCoverFn = (() => { if (!defaultCover) return false ; if (!Array .isArray (defaultCover)) return defaultCover; let lastChoice = null ; return function ( ) { let num; do { num = Math .floor (Math .random () * defaultCover.length ); } while (lastChoice === num); lastChoice = num; return defaultCover[num]; }; })(); let last = null ;for (let i = 0 ; i < 1000 ; i++) { let s = randomCoverFn (); if (last === s) { console .log ("error !" ); } last = s; }
这个办法不错,但测试下来也有缺点,可能出现[1,2,1,2,1,2]这种重复排列,不够完美。
查到资料,有一种Fisher–Yates shuffle
算法,更巧妙,链接在这里:
Fisher–Yates shuffle
Fisher–Yates shuffle 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 "use strict" ;var randomCoverFn;const createShuffleClosure = (arr ) => { const shuffledArray = [...arr]; const currentShuffleList = []; let lastChioce; const shuffle = ( ) => { let currentIndex = arr.length ; while (currentIndex !== 0 ) { const randomIndex = Math .floor (Math .random () * currentIndex); currentIndex--; const tempValue = shuffledArray[currentIndex]; shuffledArray[currentIndex] = shuffledArray[randomIndex]; shuffledArray[randomIndex] = tempValue; } return [...shuffledArray]; }; const getOneFromShuffled = ( ) => { if (currentShuffleList.length === 0 ) { do { currentShuffleList.splice (0 ); currentShuffleList.push (...shuffle ()); } while (currentShuffleList[currentShuffleList.length - 1 ] === lastChioce); } return currentShuffleList.pop (); }; return getOneFromShuffled; }; hexo.on ("generateBefore" , () => { const { cover : { default_cover : defaultCover }, } = hexo.theme .config ; if (!defaultCover) { randomCoverFn = () => false ; return ; } if (!Array .isArray (defaultCover)) { randomCoverFn = () => defaultCover; return ; } randomCoverFn = createShuffleClosure (defaultCover); });
这种算法完美解决了上述问题