随机驱逐地图值

时间:2012-11-11 23:49:33

标签: java random hashmap probability

我需要能够从包含m元素的地图中删除n元素,只能访问迭代器。我可以简单地迭代字典一次,并以概率m/n删除所有元素,但这可能会驱逐多于或少于m个项目(尽管预期项目已删除是正确的m)。

int m = 10;
int n = map.size();

Iterator<K> keys = map.keySet().iterator();
while (keys.hasNext()) {
    keys.next();
    if (random.nextDouble() < m / (double) n) {
        keys.remove();
    }
}

我一直在考虑的解决方案是在m元素被驱逐后简单地停止驱逐元素,并且在迭代结束时,如果evicted < m元素被驱逐,则驱逐剩余的m - evicted元素。第二次迭代中的{1}}个元素。我担心第二次传球在概率上是不正确的。

int m = 10;
int n = size();
int evicted = 0;

outer: while (evicted < m) {

Iterator<K> keys = keySet().iterator();
while (keys.hasNext()) {
    keys.next();
    if (random.nextDouble() < m / (double) n) {
        keys.remove();

        if (++evicted == m) {
            break outer;
        }
    }
}

或者,我可以保留一个键列表并用一次迭代对列表进行存储 - 并删除m键列表中的所有键,但是有一些内存开销我宁愿不被迫使用。此外,使用迭代器删除比通过键删除元素更快(它需要找到密钥存储在其中的存储桶,然后在列表中的位置)。是否有另一种在线算法我只能访问迭代器(不创建单独的列表)?

编辑:对于有兴趣的人,我发现了一篇详细说明如何按顺序生成随机发布的论文,以便不需要单独的排序步骤。代码是这样的(截断为整数时可能包含重复项):

int curmax = 1.0;
int[] indices = new int[m];
for (int i = indices.length; i >= 0; i--) {
    curmax = curmax * Math.pow(random.nextDouble(), 1 / (double) (i+1));
    indices[i] = (int) curmax;
}

2 个答案:

答案 0 :(得分:3)

为什么不先驱逐第一个 M 元素然后停止迭代器?迭代器中是否有一些反映会对被驱逐元素产生不必要的偏差?

如果是的话,你的双程方式将 在统计上完美无瑕。如果第一遍通过提前终止,因为在到达迭代结束之前到达了 M ,则后来的元素从未考虑过驱逐。

如果你在没有驱逐 M 元素的情况下到达迭代的末尾,迭代的第一个元素将“冒险”驱逐两次,而在迭代结束时的那些将冒险驱逐一次

如果你事先知道 N ,你可以在0到N之间建立一个 M 随机,非重复数字的列表。迭代一次,保持计数在哪里你在迭代中。如果迭代编号在您的“驱逐列表”中,则逐出该元素。

遵循该方法,您必须暂时为 M 索引位置(可能是整数)分配内存,以用于迭代过程。

答案 1 :(得分:1)

执行此操作的正确方法是以概率m / n删除每个元素,但根据结果重新规范概率(如果我们删除元素,则减少m,并且当前概率需要按元素数量缩放)可供选择)。我的java有点生疏,我无法访问编译器,所以请原谅我,如果这不起作用(但你应该能够解决它而不会有太多的麻烦我希望):

int seen = 0

Iterator<K> keys = map.keySet().iterator();
while (keys.hasNext()) {
    if (m==0)
      break;

    keys.next();
    prob = m / (double)(n-seen)  //renormalise the prob so that the total available is 1 across all remaining instances
    if (random.nextDouble() < prob) {
        keys.remove();
        m--;
    }
    seen++;
}

我希望这里的逻辑是清楚的 - 这是如何从概率为1 / n的集合中对一个元素进行采样的概括,其中一旦你拒绝了一个元素,你就可以忽略它并考虑所有元素的分布剩下的元素。这应该确保您准确地返回具有正确概率的m个元素。

修改

修正了一些拼写错误并删除了冗余变量。