有人可以告诉我这个实现变体的工作原理吗?
我对如何确保 var rand 生成的随机数(也就是我们试图访问的索引)是唯一的以确保我们进行洗牌感到困惑给定的数组。
EG。给定[1,2,3,4]我们返回[3,4,2,1]而不是[3,3,4,4],因为生成的随机数恰好重复了2和3的索引?
_.shuffle = function(array) {
var newArr = array.slice();
for (var i=array.length-1; i>0; i--) {
var rand = Math.round(Math.random() * i);
var temp = newArr[rand];
newArr[rand] = newArr[i];
newArr[i] = temp;
}
return newArr;
};
答案 0 :(得分:1)
ran
不一定是唯一的。
对于for
循环的每次迭代,混洗算法将交换数组中的两个项目。
因此,如果ran
不是唯一的,那就没问题,因为我们可以将两个项重新交换多次,而不会导致问题。
另外,请注意该数组已发生变异。因此,对于循环的每次迭代,我们操作数组的最新状态。这意味着如果我们多次交换相同的索引,我们就不会创建重复项。
答案 1 :(得分:0)
这叫做Fisher-Yates shuffle。维基百科有一篇相当精细的文章:https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
答案 2 :(得分:0)
阅读annotated version of the source:
使用Fisher-Yates shuffle的现代版本随机播放集合。
不,rand
不是唯一生成的,它可以是不同迭代中的相同数字。但是通过算法的设计,它总是指向一个非混洗元素(在[0, i]
范围内)。
答案 3 :(得分:0)
这是处理随机值的错误实现的一个很好的例子。
使用Math.round
,您得到的结果并不是真正相等的分布式,这意味着在整个范围的开始和结束时,您只需获得一半的值。
var rand = Math.round(Math.random() * i);
// ^^^^^
var _ = {},
i,
array = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'],
count = { };
_.shuffle = function (array) {
var newArr = array.slice();
for (var i = array.length - 1; i > 0; i--) {
var rand = Math.round(Math.random() * i);
var temp = newArr[rand];
newArr[rand] = newArr[i];
newArr[i] = temp;
}
return newArr;
};
array.forEach(function (a) {
count[a] = count[a] || [];
});
for (i = 0; i < 100000; i++) {
_.shuffle(array).forEach(function (a, i) {
count[a][i] = (count[a][i] || 0) + 1;
});
}
console.log(count);
&#13;
.as-console-wrapper { max-height: 100% !important; top: 0; }
&#13;
使用
分发的示例var rand = Math.floor(Math.random() * (i + 1));
// ^^^^^ ^^^
var _ = {},
i,
array = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'],
count = { };
_.shuffle = function (array) {
var newArr = array.slice();
for (var i = array.length - 1; i > 0; i--) {
var rand = Math.floor(Math.random() * (i + 1));
var temp = newArr[rand];
newArr[rand] = newArr[i];
newArr[i] = temp;
}
return newArr;
};
array.forEach(function (a) {
count[a] = count[a] || [];
});
for (i = 0; i < 100000; i++) {
_.shuffle(array).forEach(function (a, i) {
count[a][i] = (count[a][i] || 0) + 1;
});
}
console.log(count);
&#13;
.as-console-wrapper { max-height: 100% !important; top: 0; }
&#13;