我有array
我在其中取出random
件
[a, b, c, d ,...]
function getRandomItem(){
// return random item from array
}
我也有一个像这样的SQL表:
category_id
random_item
然后我想将该项添加到表中。对于每个category_id
,我想要多行随机项,例如:
category_id
1和category_id
2)以下是一些虚构的代码:
function persist(){
var a = giveRandomItem();
// $1 = a
return execute("INSERT INTO mytable (random_item) values ($1) ON CONFLICT DO NOTHING RETURNING *", a)
}
// usage
var persisted;
while(persisted === undefined){
persisted = persist();
}
问题在于它不是恒定的时间。我有可能连续5次点击DB,因为该项已经被持久化了。
对于每个类别,我预计最多5k项目,我的数组长度为400 000.所以概率很低。
我想找到一种恒定时间的方式,或者至少有一个sql命令可以尝试多个值,以便进一步降低概率。
用例
我能想到的一个简单用例是(它没用但很简单):
为用户提供了一个可以选择类别的界面。然后他们可以按下一个按钮,为其添加一个随机项目。 有多个用户,每个用户单独行动。因此,用户1可以将随机项添加到类别1,而用户2同时将随机项添加到类别2
修改
我最终做了这样的事情:
在应用程序级别:
shuffle(array);
function getRandomItem(seed, inc){
let index = (seed + inc) % array.length;
return array[index]
}
// usage:
let seed = item.category_id
let inc = category.item_count
这样我没有重复,因为我说项目的数量低于数组的长度。此外,这些项似乎是随机的,因为该类别的id用作增量开始的种子。然而,这只是起点,因此它并不是随机的,但适用于我的用例。
答案 0 :(得分:2)
为了保证您不会遇到冲突(违反唯一约束),您应该改变您的方法。您应该一次生成所有5K项目(然后批量插入),而不是一次生成一个随机项目。批量插入也会大大加快速度。
如何从400K项目的数组中生成5K随机项?
一种方法是shuffle the array并采用前5K元素。然后是接下来的5K元素,依此类推。这也可以保证单独的批次不具有重复元素(直到所有400K都耗尽并且再次从数组的开头开始)。
如果您希望元素有可能在批次之间重复,则在批次之间重新排列数组。
在评论中讨论后,您似乎需要一个生成Cyclic permutations的算法。对于DB中的每个类别存储,该算法的起始种子/内部状态知道如何以这样的方式继续挑选400K数组的元素,使它们看起来是随机的,但不要重复直到该类别的所有400K元素都是拾取。