如何在改组之前保存数组的旧状态
How to save the old state of an array before shuffling
我有一个包含 50 个对象的数组。
每个对象包含一个包含 4 个元素的数组:
var all = [{
question: "question 1 goes here",
options: ["A", "B", "C", "D"]
}, ... {
question: "question 50",
options: ["A", "B", "C", "D"]
}]
我想 select 10 个元素随机保存到另外两个数组,其中一个数组我想随机播放选项。但是当洗牌时,两个数组都会受到影响。
var selected = [];
var shuffled = [];
for(let i = 0; i < 10; i++) {
let rand = Math.floor(Math.random() * all.length);
selected.push(all[rand]);
shuffled.push(all[rand]);
all.splice(rand, 1);
for(let j = 3; j > 0; j--) {
let rand2 = Math.floor(Math.random() * j);
[
shuffled[i].options[j],
shuffled[i].options[rand2]
] = [
shuffled[i].options[rand2],
shuffled[i].options[j]
];
}
}
console.log(selected); // is shuffled too
console.log(shuffled);
我该如何预防?
我觉得我遗漏了一些非常简单的东西,但我找不到它。
尝试使用从您的对象制作硬拷贝的传播功能all
var selected = [];
var shuffled = [];
// Make a copy of all by using the spread function:
// You can later use this variable since it will contain the content of the
// initial all variable
const allCopy = [...all];
for (let i = 0; i < 10; i++) {
let rand = Math.floor(Math.random() * all.length);
selected.push(all[rand]);
shuffled.push(all[rand]);
all.splice(rand, 1);
for (let j = 3; j > 0; j--) {
let rand2 = Math.floor(Math.random() * j);
[shuffled[i].options[j], shuffled[i].options[rand2]] = [shuffled[i].options[rand2], shuffled[i].options[j]];
}
}
console.log(selected); // is shuffled too
console.log(shuffled);
您需要为所选对象及其 options
数组创建新实例:
// shuffle array a in place (Fisher-Yates)
// optional argument len (=a.length):
// reduced shuffling: shuffling is done for the first len returned elements only,
// array a will be shortened to length len.
function shuffle(a, len=a.length){
for(let m=a.length,n=Math.min(len,m-1),i=0,j;i<n;i++){
j=Math.floor(Math.random()*(m-i)+i);
if (j-i) [ a[i],a[j] ] = [ a[j],a[i] ]; // swap 2 array elements
}
a.length=len;
return a;
}
const all=[...new Array(50)].map((_,i)=>({question:"Question "+(i+1), options:["A","B","C","D"]}));
const selected = shuffle([...all],10), // return first 10 shuffled elements only!
shuffled = selected.map(o=>({...o,options:shuffle([...o.options])}));
console.log(selected) // is no longer shuffled!
console.log(shuffled);
我将洗牌算法委托给一个单独的函数 (shuffle()
) 并将其应用两次:第一次是 all
数组以确保我们不会在我们的“随机”中得到任何重复项选择,然后到包含在其切片对象中的 options
数组。函数 shuffle(a,len)
对数组 a
进行排序。我再次将其设为 return 数组引用纯粹是为了方便,因为它可以帮助我保持代码更紧凑。可选参数 len
将导致数组 a
缩短为 len
随机元素(仍然“原地”:输入数组也会受到影响!)。
因此,为了保留我的“输入”数组,我每次通过应用 ...
运算符调用函数时都会创建新的数组实例:
shuffled = shuffle([...all],10);
...
shuffle([...o.options])
我有一个包含 50 个对象的数组。
每个对象包含一个包含 4 个元素的数组:
var all = [{
question: "question 1 goes here",
options: ["A", "B", "C", "D"]
}, ... {
question: "question 50",
options: ["A", "B", "C", "D"]
}]
我想 select 10 个元素随机保存到另外两个数组,其中一个数组我想随机播放选项。但是当洗牌时,两个数组都会受到影响。
var selected = [];
var shuffled = [];
for(let i = 0; i < 10; i++) {
let rand = Math.floor(Math.random() * all.length);
selected.push(all[rand]);
shuffled.push(all[rand]);
all.splice(rand, 1);
for(let j = 3; j > 0; j--) {
let rand2 = Math.floor(Math.random() * j);
[
shuffled[i].options[j],
shuffled[i].options[rand2]
] = [
shuffled[i].options[rand2],
shuffled[i].options[j]
];
}
}
console.log(selected); // is shuffled too
console.log(shuffled);
我该如何预防?
我觉得我遗漏了一些非常简单的东西,但我找不到它。
尝试使用从您的对象制作硬拷贝的传播功能all
var selected = [];
var shuffled = [];
// Make a copy of all by using the spread function:
// You can later use this variable since it will contain the content of the
// initial all variable
const allCopy = [...all];
for (let i = 0; i < 10; i++) {
let rand = Math.floor(Math.random() * all.length);
selected.push(all[rand]);
shuffled.push(all[rand]);
all.splice(rand, 1);
for (let j = 3; j > 0; j--) {
let rand2 = Math.floor(Math.random() * j);
[shuffled[i].options[j], shuffled[i].options[rand2]] = [shuffled[i].options[rand2], shuffled[i].options[j]];
}
}
console.log(selected); // is shuffled too
console.log(shuffled);
您需要为所选对象及其 options
数组创建新实例:
// shuffle array a in place (Fisher-Yates)
// optional argument len (=a.length):
// reduced shuffling: shuffling is done for the first len returned elements only,
// array a will be shortened to length len.
function shuffle(a, len=a.length){
for(let m=a.length,n=Math.min(len,m-1),i=0,j;i<n;i++){
j=Math.floor(Math.random()*(m-i)+i);
if (j-i) [ a[i],a[j] ] = [ a[j],a[i] ]; // swap 2 array elements
}
a.length=len;
return a;
}
const all=[...new Array(50)].map((_,i)=>({question:"Question "+(i+1), options:["A","B","C","D"]}));
const selected = shuffle([...all],10), // return first 10 shuffled elements only!
shuffled = selected.map(o=>({...o,options:shuffle([...o.options])}));
console.log(selected) // is no longer shuffled!
console.log(shuffled);
我将洗牌算法委托给一个单独的函数 (shuffle()
) 并将其应用两次:第一次是 all
数组以确保我们不会在我们的“随机”中得到任何重复项选择,然后到包含在其切片对象中的 options
数组。函数 shuffle(a,len)
对数组 a
进行排序。我再次将其设为 return 数组引用纯粹是为了方便,因为它可以帮助我保持代码更紧凑。可选参数 len
将导致数组 a
缩短为 len
随机元素(仍然“原地”:输入数组也会受到影响!)。
因此,为了保留我的“输入”数组,我每次通过应用 ...
运算符调用函数时都会创建新的数组实例:
shuffled = shuffle([...all],10);
...
shuffle([...o.options])