0

我有一个包含 50 个对象的数组作为元素。

每个对象包含一个由 4 个元素组成的数组:

var all = [{
    question: "question 1 goes here",
    options: ["A", "B", "C", "D"]
}, ... {
    question: "question 50",
    options: ["A", "B", "C", "D"]
}]

我想随机选择 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);

我该如何防止呢?

我觉得我错过了一些非常简单的东西,但我无法发现它。

4

2 回答 2

0

尝试使用从您的对象制作硬拷贝的传播功能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);

于 2021-08-16T10:55:29.400 回答
0

您需要为所选对象及其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 算法委托给一个单独的函数 ( shuffle()) 并应用了两次:首先是all数组,以确保我们在“随机”选择中没有任何重复项,然后是options包含在其切片对象中的数组。该函数对shuffle(a,len)数组a进行就地排序。我让它再次返回数组引用纯粹是为了方便,因为它可以帮助我保持我的代码更紧凑。可选参数len将导致数组a缩短为len随机元素(仍然“原地”:输入数组也会受到影响!)。

因此,为了保留我的“输入”数组,我每次通过应用...运算符调用函数时都创建了新的数组实例:

shuffled = shuffle([...all],10);
...
shuffle([...o.options])
于 2021-08-16T11:16:00.030 回答