我有一系列用户需要提供产品,例如:
值的数量总是在变化 - 第一次执行分配时,可能只有一个值,第二次是三个值。
这些值必须进行洗牌和分发,同时确保个人不会获得相同的值两次。
到目前为止,我设法做的就是对阵列进行洗牌,并为每个用户提供十种产品:
var users = ["user1", "user2", "user3"];
var products = ["p1", "p2", "p3", "p4", "p5", "p6", "p7", "p8", "p9", "p10","p11", "p12", "p13", "p14", "p15", "p16", "p17", "p18", "p19", "p20", "p21", "p22", "p23", "p24", "p25", "p26", "p27", "p28", "p29", "p30"];
function shuffle(array) {
var currentIndex = array.length, temporaryValue, randomIndex;
while (0 != currentIndex) {
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;
temporaryValue = array[currentIndex];
array[currentIndex] = array[randomIndex];
array[randomIndex] = temporaryValue;
}
return array;
}
i = 0;
while (i < users.length) {
newArray = (shuffle(products)).slice(0, 10)
console.log(users[i++] + ' products: ' + newArray);
}
结果:
user1 products: p5,p6,p13,p2,p19,p22,p8,p20,p27,p28
user2 products: p6,p30,p22,p9,p25,p2,p7,p17,p19,p10
user3 products: p20,p25,p23,p4,p28,p9,p12,p14,p21,p17
答案 0 :(得分:0)
这个问题的难点在于您希望分发的产品比产品多一些,因此少数产品会归因于多个用户。然而,您还希望均匀地分发产品,并确保没有人获得重复的产品。
为了有效地做到这一点,即在用户和产品的线性时间内,需要更多的代码。
以下算法将坚持:
function shuffled(arr) {
// Does NOT alter the given array, but returns new one
arr = arr.slice();
var i = arr.length;
while (i) {
var j = Math.floor(Math.random() * i--);
[ arr[i], arr[j] ] = [ arr[j], arr[i] ];
}
return arr;
};
function distribute(products, users) {
// Cases with only one possible outcome:
if (users.length === 0) return {};
if (users.length === 1) return { [users[0]]: shuffled(products) };
// We will distribute about 20% of the products twice
var distributeCount = Math.ceil(products.length * 1.2);
// Create object structure to return: key is user name,
// value is set of products
var possessions = users.reduce( (acc, user) =>
Object.assign(acc, { [user]: new Set() }), {} );
// Order of users in which products will be assigned
var usersLeft = shuffled(users);
while (usersLeft.length < distributeCount)
usersLeft = usersLeft.concat(usersLeft);
usersLeft.length = distributeCount; // clip array to exact size
// Order of products in which they will be assigned; double length
var productsLeft = shuffled(products).concat(shuffled(products));
// Assign products to users
while (usersLeft.length) {
product = productsLeft.pop();
user = usersLeft.pop();
if (possessions[user].has(product)) { // not allowed to add again
if (usersLeft.length) { // not the very last product distribution
// swap with next user, as others do not have this product
[ user, usersLeft[usersLeft.length-1] ] =
[ usersLeft[usersLeft.length-1], user ];
} else {
// The very last product distribution:
// pick another product: this will eventually work, as 80%
// of the products are available,
// and a user only has at most 50% of them.
do {
product = productsLeft.pop();
if (!product) throw "Could not find product for user";
} while (possessions[user].has(product));
}
}
possessions[user].add(product);
}
// Turn Sets into Arrays
for (user in possessions) possessions[user] = [...possessions[user]];
return possessions;
}
var users = ["user1", "user2", "user3"];
var products = ["p1", "p2", "p3", "p4", "p5", "p6", "p7", "p8", "p9", "p10","p11",
"p12", "p13", "p14", "p15", "p16", "p17", "p18", "p19", "p20", "p21",
"p22", "p23", "p24", "p25", "p26", "p27", "p28", "p29", "p30"];
var result = distribute(products, users);
console.log(result);