🦁
配列の要素をランダムにシャッフルさせたい
やりたいこと
JavaScriptの配列の要素を呼び出すたびに要素数を変えずに、ランダムな順番の配列を生成する関数を生成したい
ユースケース
ブラウザをリロードするたびにリストの順番を、ランダムに入れ替えたい時なんかに使用できます。
たとえば、ホテルの情報をリストで表示しているサイトがあったときに、いつも特定のホテルだけが一番上に表示されていたら、そのホテルだけにアクセスやクリックが集中してしまいます。
もし他のホテル会社さんが、後発組として、そのサイトに情報を掲載したとしても、シャッフルの実装がされていなければ、ずっとそのホテルの情報が一番下に情報が表示されてしまいます。
そんなサイトでは、後発組として情報を掲載する意味がありませんよね。
みたいなサイトの開発を担当したときに、以下に紹介した要素の順番を乱数を用いて並び替える実装を用います。
実現方法
今回は、以下の2つを用いた実装方法を紹介します。
- for文を用いて実装する方法
- reduce関数を用いて実装する方法
for文を用いた実装方法
/**
* 配列の要素の値を変更せずに要素の順番を並べ替える関数
* (e.g) [0,1,2,3,4] => [1,3,2,0,4]
*/
const shuffleArray = (array) => {
const cloneArray = [...array]
for (let i = cloneArray.length - 1; i >= 0; i--) {
let rand = Math.floor(Math.random() * (i + 1))
// 配列の要素の順番を入れ替える
let tmpStorage = cloneArray[i]
cloneArray[i] = cloneArray[rand]
cloneArray[rand] = tmpStorage
}
return cloneArray
}
// 要素が数値の配列でもいける
console.log(shuffleArray([0,1,2,3,4]));
// expected output : [0,3,4,1,2]
// 要素が文字列の配列でもいける
console.log(shuffleArray(['JavaScript','React','Vue']));
// expected output : ['React','JavaScript','Vue']
// 要素がオブジェクトの配列でもいける
console.log(shuffleArray([{id:1,age:23},{id:2,age:24},{id:3,age:25}]));
// expected output : [{id:2,age:24},{id:1,age:23},{id:3,age:25}]
reduce関数を用いた実装方法
// reduceを用いた実装方法
const shuffleArray = (array) => {
const cloneArray = [...array];
const result = cloneArray.reduce((_,cur,idx) => {
let rand = Math.floor(Math.random() * (idx + 1));
cloneArray[idx] = cloneArray[rand]
cloneArray[rand] = cur;
return cloneArray
})
return result;
}
console.log(shuffleArray([1,2,3,4,5]))
// expected output : [3,2,5,1,4]
簡単に解説
Math.floor()
実引数に与えられた数値以下の「整数」を返します
console.log(Math.floor(5.95))
// 出力結果 : 5
console.log(Math.floor(6.78))
// 出力結果 : 6
console.log(Math.floor(7.53))
// 出力結果 : 7
Math.random()
0以上1未満の「乱数」を返します
console.log(Math.random())
// 出力結果 : 0.10693731104538573
console.log(Math.random())
// 出力結果 : 0.38645632869127056
console.log(Math.random())
// 出力結果 : 0.9264442420785377
上記、2つを用いれば、ランダムな整数を返すことが実現できます!
最後に
他にもこんな良い実装方法があるよ、とかもし知見のある強い方がいらっしゃったらコメントいただけると嬉しいです!!
Discussion
sort
をこんな感じで使う方法は思いつきませんでした。ありがとうございます!2024年10月現在だと Array.prototype.toSortedが使えそうなので、破壊的変更を考慮することなくかけそうですね。