【问题标题】:Secret Santa Javascript: How to get a shuffled array with the original indexes randomized so no positions are the same?Secret Santa Javascript:如何获得一个随机排列的原始索引的随机数组,因此没有位置相同?
【发布时间】:2020-11-26 10:37:25
【问题描述】:

我正在尝试制作一个秘密圣诞老人,其中我有一个参与人员的列表,然后我只单击一次按钮,在每个名字前面我都会得到他们将要送礼物的人的名字。 要求是一个人没有得到自己的礼物,并且只送礼物一次。

我尝试在不创建新数组的情况下对数组进行洗牌,现在我正在尝试实现以下逻辑(最后的完整代码):

  • 我有一个包含参与人员的数组:giveArr
  • 我复制这个数组并将其命名为 toReceiveArr
  • 通过循环,我通过 toReceiveArr 并从
  • 中删除 personGiving
var toReceiveArr
var personGiving = toReceiveArr.splice(j,0);
  • personReceiving 礼物是随机从 toReceiveArr 中取出的,并添加到第三个数组 - receivingArr - 其中人的名字是放置在与原始 giveArr 不同的位置,因此这是随机列表
var random = Math.floor(Math.random()*toReceiveArr.length);
var personReceiving = toReceiveArr[random];
receivingArr.push(personReceiving);
  • 在此之后,我从 toReceiveArr 中删除接收礼物的人,并将赠送礼物的人添加回 toReceiveArr,以便可以将其包含在下一个 for 循环中并接收礼物
toReceiveArr.splice(random,1); 
toReceiveArr.splice(j,0, personGiving); 

所以最后我想要这样的东西:
giveArr = [杰森,迈克尔,苏珊]
接收Arr = [迈克尔,苏珊,杰森]

但是,当我尝试这样做时,我仍然会得到重复的捐赠者和收到自己礼物的人。我是初学者,但到目前为止,我对 HTML 部分或 EventListeners 没有任何问题。但是JS失败了。我的错误在哪里?

var give = document.getElementsByTagName("li");
var giveArr= [];
var toReceiveArr = [];
var receivingArr =[];

for (var i=0; i<give.length; i++){
    giveArr.push(give[i].textContent); }
toReceiveArr = giveArr.concat();

for(var j=giveArr.length-1;j>=0;j--){ 
    var personGiving = toReceiveArr.splice(j,0); 
    var random = Math.floor(Math.random()* toReceiveArr.length);
    var personReceiving = toReceiveArr[random];

    receivingArr.push(personReceiving); 
    toReceiveArr.splice(random,1); 
    toReceiveArr.splice(j,0, personGiving);
}

【问题讨论】:

    标签: javascript arrays


    【解决方案1】:

    正如我从您的问题中了解到的那样,您需要一个输出数组,其名称在“li”标签中具有以下两个条件:

    1- 我们没有重复的名字

    2-每个输出数组项的名称必须与具有相同位置的输入数组不同,例如如果名字是“jason”,则输出数组的第一项不能是“jason”。

    对于这些问题,我使用了 javascript 的“filter()”方法而不是“splice”方法。您可以从下面的链接中了解有关此方法的更多信息:

    https://www.w3schools.com/jsref/jsref_filter.asp

    代码如下:

    let give = document.getElementsByTagName("li");
    let giveArr= [];
    let receivingArr =[];
    
    
    for (var i=0; i<give.length; i++){
        giveArr.push(give[i].textContent); 
    }
    
    let lastName = give[give.length - 1].textContent;
    
    let lenghtVar = giveArr.length
    
    // ------------------------------
    // functions that are used in "filter()" javascript method
    function stringCheck(str) {
        // this filter is used to force each li element not give "itself" name : jason:jason
        return str != giveArr[0];
    }
    
    function deleteCheck(str2) {
        // this filter is used to see that we don't have repeated name
        let lastItem = receivingArr.length - 1;
        return str2 == receivingArr[lastItem];
    }
    
    function deleteCheck2(str3) {
        // this filter is used to delete repeated name from search
        let lastItem = receivingArr.length - 1;
        return str3 != receivingArr[lastItem];
    }
    
    function lastCheck(str4) {
        // this filter is used to check that last name is used before we reach to last item in the for loop
        return str4 == lastName;
    }
    // ------------------------------
    
    
    for (let i = 0; i<lenghtVar; i++) {
        if(i == lenghtVar-1) {
            /* this "if" checks that the last name has been used before the last iteration, otherwise it replace it with the one previous last name */
            let new3Arr = receivingArr.filter(lastCheck);
            if (new3Arr.length == 0) {
        
                receivingArr.splice(lenghtVar-2, 0, lastName);
                console.log(receivingArr);
                break;
            }
        }
        
        let newArr = giveArr.filter(stringCheck);
        let randomNum = Math.floor(Math.random()* newArr.length);
        receivingArr.push(newArr[randomNum]);
        
        let deletArr = receivingArr.filter(deleteCheck);
    
        while (deletArr.length>1) {
            /* this "while" loop is checking that we do not have repeated names */
             let new2Arr = newArr.filter(deleteCheck2);
    
             let randomNum2 = Math.floor(Math.random()* new2Arr.length);
             receivingArr.pop();
             receivingArr.push(new2Arr[randomNum2]);
             deletArr = receivingArr.filter(deleteCheck);
    
        }
        
        console.log(receivingArr);
        
        giveArr.push(giveArr[0]);
        giveArr.shift();
    } // end of for
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <title>random-array</title>
    </head>
    <body>
       <div id="names">
       <ul>
           <li>jason</li>
           <li>Michael</li>
           <li>susan</li>
           <li>oliver</li>
           <li>jack</li>
       </ul>
       </div>
       
       <script src="javacode.js"></script>
        
    </body>
    </html>

    代码中的“receivingArr”数组是可用于您自己的项目的“输出”数组。我用 3 和 5“li”标签测试了代码。每次刷新浏览器时,它都会生成具有这两个条件的随机列表。

    【讨论】:

    • 非常感谢这个解决方案,它有效!不会撒谎,我还没有完全理解过滤器在循环中的应用。我现在明白了,我在向数组中添加项目时错误地使用了拼接(因为索引),但是你知道我原来解决问题的方法有什么问题吗?
    • 我认为可能对您有所帮助的一件事是了解“javascript 变异”,您可以搜索它。但是对于您的代码,使用“splice”之类的方法会更改原始数组,如果您对这些数组使用“console.log()”,您会注意到元素的数量和它们的值正在发生变化每次你使用这样的方法时,不仅仅是“splice”,其他一些“javascript”方法如“push”具有此功能,另一方面其他一些方法如“filter and map”不会改变原始数组。
    猜你喜欢
    • 2021-12-30
    • 1970-01-01
    • 2021-05-07
    • 2022-11-21
    • 1970-01-01
    • 1970-01-01
    • 2011-11-22
    • 1970-01-01
    • 2020-12-10
    相关资源
    最近更新 更多