如何多次平均获取数组的随机元素?

How to get random elements of an array multiple times equally?

提问人:Phil-Absynth 提问时间:11/3/2023 最后编辑:jonrsharpePhil-Absynth 更新时间:11/4/2023 访问量:63

问:

我有一个月的表,表的每一天都有一行,还有一个带有名称的数组。对于每一天,都应该从数组中随机选择一个名称,而如果可能的话,每个名称都应该选择大约相同的次数。

以下函数检查数组中的每个用户在某一天是否可用,如果没有,则排除名称。

function generateRandomSchedule(month) {
    // some more code including variable declaration here

    for(let i=1; i<daysInMonth+1; i++) {
        let date = `${moment(i, 'D').format('DD')}.${monthNumber}.`;
        // filter required keys
        const keys = Object.keys(localStorage).filter(key => key.includes(date) && !key.startsWith(month));
        let excludeUsers = [];
        keys.forEach((key) => {
            let keyValue = localStorage.getItem(key);
            // check if user is available for the certain day
            if(key.includes('Urlaub') && dutyUserArray.includes(keyValue)) {
                excludeUsers.push(keyValue);
            }
            if(key.includes('Spaet') && dutyUserArray.includes(keyValue)) {
                excludeUsers.push(keyValue);
            }
        })
        // remove unavailable users from array
        let updatedArray = dutyUserArray.filter(user => !excludeUsers.includes(user));

        // get random user from the available users
        let randomName = updatedArray[Math.floor(Math.random() * updatedArray.length)];

        // some more code to add randomName to table here
    }
}

到目前为止,这段代码工作正常,只是它不均匀地选择随机数组元素,例如 name1 已添加到表中 6 次,而 name2 仅添加一次,name3 添加 4 次。

JavaScript的

评论

0赞 Krokodil 11/3/2023
看看这里的答案 - stackoverflow.com/questions/63800423/...,它们似乎很有帮助
0赞 phatfingers 11/3/2023
您可以跟踪每个名称的使用次数,按该数量排序,然后从与最低数量匹配的名称中随机选择。updatedArray
0赞 Wyck 11/3/2023
@phatfingers那行不通。想象一下,两个人有一个为期两天的月份,其中 Alice 和 Bob 在 1 日都有空,但只有 Alice 在 2 日有空(Bob 在 2 日不可用)。如果 Alice 在 1 日被随机选中,我们不能在 2 日选择 Bob 以使其相等。将它们排列为相等的唯一方法是让 Bob 在 1 日被选中,Alice 在 2 日被选中。
0赞 James 11/3/2023
由于不可用天数,您需要先分配这些天数,然后对“每个人都有空”天数的分布进行加权以进行补偿。

答:

0赞 phatfingers 11/4/2023 #1

我将首先确定具有最小可用天数的用户,以及池中的用户数。如果 ,则将每个用户的时间复制到列表中,然后添加“虚拟”用户以使列表与当月的天数匹配,否则均匀复制循环样式,直到匹配天数。在两个被欺骗用户列表之间执行“稳定婚姻”匹配(参见 Gale-Shapley 算法),直到天。minDays*poolSize <= monthSizeminDaysmonthSize - minDays*poolSize

创建一个新列表,其中所有用户省略了与先前的最小可行天数匹配的用户,并针对任何不匹配或虚拟匹配的天数对该组用户重复上述过程。

继续这样做,直到所有日期都匹配。在这一点上,时间表可能无法解决。简单来说,您可以有一个包含 1 个用户的池,在一个月的 30 天内有 1 天可用。

解决后,迭代匹配的用户日,在允许的情况下在用户日之间执行随机交换。dutyUserArray