背景 今天打开博客页面,发现主页这么呈现:
很明显是因为随机封面算法是真随机,于是找到现在在用的主题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); }); 
这种算法完美解决了上述问题