【问题标题】:Is there random nextInt with weights?是否有随机的 nextInt 权重?
【发布时间】:2015-04-11 21:57:35
【问题描述】:

我正在使用随机类生成 1 到 5 之间的随机数,例如 myrandom.nextInt(6),它工作正常,但是我想知道是否有办法给特定数字赋予权重以增加它是出现的概率,假设不是 %20 的概率,我希望数字“4”具有 %40 的概率,而其他数字 1、2、3、5 平均共享 %60 概率的其余部分。有办法吗?

提前致谢。

【问题讨论】:

  • 不,没有。你必须自己做这件事。选择一个介于 1 和数字权重之和之间的随机数,然后将结果映射到与其对应的数字。
  • @Ingo Bürk,你能给我一个做这个映射的例子吗?
  • @Faruk 我发布了一个快速演示作为答案。

标签: java random


【解决方案1】:

我使用一个数组。例如

int[] arr = {4, 4, 4, 5, 5, 6};
int a = arr[random.nextInt(arr.length)];

要获得更动态的解决方案,请试试这个。权重不必相加为任何特定值。

public static <T> T choice(Map<? extends T, Double> map) {
    if (map == null || map.size() == 0)
        throw new IllegalArgumentException();
    double sum = 0;
    for (double w : map.values()) {
        if (Double.compare(w, 0) <= 0 || Double.isInfinite(w) || Double.isNaN(w))
            throw new IllegalArgumentException();
        sum += w;
    }
    double rand = sum * Math.random();
    sum = 0;
    T t = null;
    for (Map.Entry<? extends T, Double> entry : map.entrySet()) {
        t = entry.getKey();
        if ((sum += entry.getValue()) >= rand)
            return t;
    }
    return t;
}

您可以随时轻松地从地图中添加/删除/更改条目。以下是您如何使用此方法的示例。

Map<Integer, Double> map = new HashMap<>();
map.put(1, 40.0);
map.put(2, 50.0);
map.put(3, 10.0);
for (int i = 0; i < 10; i++)
    System.out.println(choice(map));

【讨论】:

  • 我会不断增加、减少概率,甚至删除一些数字,所以使用静态数组是有问题的,即使我使用字符串缓冲区之类的东西,它仍然是因为我必须在添加之前进行一些计算元素到字符串缓冲区(知道我将添加多少)
  • @Faruk 好的,我会考虑一个更动态的解决方案。
【解决方案2】:

pbadcefp 的答案可能是最简单的。由于您在 cmets 中声明您需要它是“动态的”,因此这是另一种方法。请注意,权重基本上指定了要从中选择的数字在数组中出现的频率

public int weightedRandom( Random random, int max, Map<Integer, Integer> weights ) {
    int totalWeight = max;
    for( int weight : weights.values() ) {
        totalWeight += weight - 1;
    }

    int choice = random.nextInt( totalWeight );
    int current = 0;
    for( int i = 0; i < max; i++ ) {
        current += weights.containsKey( i ) ? weights.get( i ) : 1;
        if( choice < current ) {
            return i;
        }
    }

    throw new IllegalStateException();
}

示例用法:

Map<Integer, Integer> weights = new HashMap<>();
weights.put( 1, 0 ); // make choosing '1' impossible
weights.put( 4, 3 ); // '4' appears 3 times rather than once

int result = weightedRandom( new Random(), 5, weights );

基本上,这相当于pbadcefp的解决方案应用于数组{ 0, 2, 3, 4, 4, 4 }

如果你想使用百分比,你必须适应这个。只需相应地计算权重。另外,我没有对此进行测试,因此您可能需要更广泛地对其进行测试。

这绝不是一个完整的解决方案,但比起完整的解决方案,我更喜欢提供一些东西来解决,因为你应该自己做一些工作。

我也将继续记录并说恕我直言,这是过度设计的;但你想要这样的东西。

【讨论】:

    【解决方案3】:

    您必须生成更大范围的数字(例如从 1 到 100)并使用范围来返回您真正想要的数字。例如:(在伪代码中)

    r = randint(1..100)
    if (r >= 1 && r <= 20) // 20% chance
        return 1
    else if (r >= 21 && r <= 60) // 40% chance
        return 2
    

    等等

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-08-10
      • 1970-01-01
      • 2019-02-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-29
      相关资源
      最近更新 更多