如何将内容ID数组按递减数量分配给用户ID数组?
基于幂律分布的内容ID分配方案
核心思路
要实现「首位用户分配最多、多数末尾用户分配0个」的需求,**幂律分布(如Zipf定律)**是最匹配的数学模型——它天然符合「少数个体占据大量资源,多数个体资源极少甚至为0」的长尾特征,完全适配你的需求。
具体实现步骤
1. 确定分配规则与参数
我们采用指数衰减模型(计算简单,长尾效果接近Zipf定律):
- 给每个用户按索引(从0开始,对应第一个用户)计算权重:
weight(i) = e^(-k * i / totalUsers),其中k为衰减系数,值越大,内容向头部用户集中的速度越快,更多末尾用户会分配到0个内容。 - 先计算所有用户的权重总和,归一化后得到每个用户的分配比例,乘以总内容数100000得到初始分配数量。
- 设置最小阈值(如0.5),分配数量低于阈值的用户直接设为0,确保多数末尾用户无内容。
2. 代码实现
function distribute(userIds, contentIds) { const totalUsers = userIds.length; // 10000 const totalContents = contentIds.length; // 100000 const decayCoeff = 0.0012; // 调整此值控制衰减速度,越大衰减越快 const minThreshold = 0.5; // 低于该值的分配数直接设为0 // 计算每个用户的权重与总权重 const weights = []; let totalWeight = 0; for (let i = 0; i < totalUsers; i++) { const weight = Math.exp(-decayCoeff * i); weights.push(weight); totalWeight += weight; } // 计算初始分配数,同时截断低分配用户 const allocations = []; let allocatedTotal = 0; for (let i = 0; i < totalUsers; i++) { const count = (weights[i] / totalWeight) * totalContents; const finalCount = count >= minThreshold ? Math.floor(count) : 0; allocations.push(finalCount); allocatedTotal += finalCount; } // 修正分配误差:将剩余内容补到头部用户,确保总数为100000 let remaining = totalContents - allocatedTotal; let idx = 0; while (remaining > 0 && idx < totalUsers) { if (allocations[idx] > 0) { allocations[idx]++; remaining--; } idx++; } // 按分配数分发内容ID const result = {}; let contentPointer = 0; for (let i = 0; i < totalUsers; i++) { const userId = userIds[i]; const count = allocations[i]; result[userId] = count === 0 ? [] : contentIds.slice(contentPointer, contentPointer + count); contentPointer += count; } return result; } // 测试示例 const userIds = Array.from({length: 10000}, (_, i) => `user_${i}`); const contentIds = Array.from({length: 100000}, (_, i) => `content_${i}`); const distributionResult = distribute(userIds, contentIds); // 验证结果 console.log('首位用户内容数:', distributionResult.user_0.length); console.log('末尾用户内容数:', distributionResult.user_9999.length); // 输出0
3. 参数调整说明
decayCoeff:控制内容向头部集中的速度,比如调到0.0015时,前1000个用户即可分配完绝大多数内容,剩余9000个用户均为0;调到0.0008时,会有更多用户分到少量内容。- 若想要更极端的头部集中效果,可改用Zipf分布,将权重公式改为
weight(i) = 1 / Math.pow(i + 1, 1.5)(指数1.5可按需调整),后续计算逻辑不变。
替代方案:线性递减+截断
如果偏好更直观的规则,可采用线性递减模型:
- 指定前
M个用户按线性递减分配(从maxCount降到1),剩余10000-M个用户分配0。 - 通过公式
M*(maxCount + 1)/2 = 100000计算参数,比如M≈447时,maxCount≈447,总和刚好接近100000,剩余9553个用户均为0。但这种方式的长尾效果不如幂律自然。
内容的提问来源于stack exchange,提问作者mesqueeb
相关产品推荐
相关产品推荐

