1、洗牌算法的概念:
Fisher-Yates ,最早提出这个洗牌方法的是 Ronald A. Fisher 和 Frank Yates,即 Fisher–Yates Shuffle,
其基本思想就是从原始数组中随机取一个之前没取过的数字到新的数组中,具体如下:
- 1. 初始化原始数组和新数组,原始数组长度为n(已知);
- 2. 从还没处理的数组(假如还剩k个)中,随机产生一个[0, k)之间的数字p(假设数组从0开始);
- 3. 从剩下的k个数中把第p个数取出;
- 4. 重复步骤2和3直到数字全部取完;
- 5. 从步骤3取出的数字序列便是一个打乱了的数列。
保证每个数出现在任意一个位置的概率相同,也就是说在n!个的排列中,每一个排列出现的概率相同。
下面证明其随机性,即每个元素被放置在新数组中的第i个位置是1/n(假设数组大小是n)。
证明:一个元素m被放入第i个位置的概率P = 前i-1个位置选择元素时没有选中m的概率 * 第i个位置选中m的概率,
2、JavaScript代码演示:
//洗牌算法
function flushArr(arr){
const endIndex = arr.length - 2;
for(let i=0;i<=endIndex;i++){
const j = i + Math.floor(Math.random() * (arr.length - i));
[arr[i],arr[j]] = [arr[j],arr[i]];
}
return arr;
}
const a = Array.from({length:9},(v,i)=>i);
console.log(a);
console.log(flushArr(a));
3、补充说明:
Array.from()方法就是将一个类数组对象或者可遍历对象转换成一个真正的数组。
那么什么是类数组对象呢?所谓类数组对象,最基本的要求就是具有length属性的对象。
let arrayLike = {
0: 'tom',
1: '15',
2: '男',
3: ['jane','john','Mary'],
'length': 4
}
let arr = Array.from(arrayLike)
console.log(arr) // ['tom','15','男',['jane','john','Mary']]
那么,如果将上面代码中length属性去掉呢?实践证明,答案会是一个长度为0的空数组。
这里将代码再改一下,就是具有length属性,但是对象的属性名不再是数字类型的,而是其他字符串型的,代码如下:
let arrayLike = {
'name': 'tom',
'age': '25',
'sex': '男',
'friends': ['jane','john','Mary'],
length: 4
}
let arr = Array.from(arrayLike)
console.log(arr) // [ undefined, undefined, undefined, undefined ]
由此可见,要将一个类数组对象转换为一个真正的数组,必须具备以下条件:
1、该类数组对象必须具有length属性,用于指定数组的长度。如果没有length属性,那么转换后的数组是一个空数组。
2、该类数组对象的属性名必须为数值型或字符串型的数字
Array.from
还可以接受第二个参数,作用类似于数组的map
方法,用来对每个元素进行处理,将处理后的值放入返回的数组。如下:
let arr = [12,45,97]
let set = new Set(arr)
console.log(Array.from(set, item => item + 1)) // [ 13, 46, 98]
array.map(function(currentValue,index,arr), thisValue)