从反向权重映射中选择一个随机值

时间:2018-05-24 08:36:16

标签: java random

我正在使用带有合格字词的地图进行我正在开发的刽子手游戏。地图中的整数存储选择单词的时间,因此在开始时地图如下所示:

alabanza 0
esperanza 0
comunal 0
aprender 0
....

经过一些游戏后,地图会像这样

alabanza 3
esperanza 4
comunal 3
aprender 1
....

我想随机选择下一个单词,但选择较少的单词会被选中的概率更大。

我读过Java - Choose a random value from a HashMap but one with the highest integer assigned,但情况相反。

我还以为我可以使用带有重复单词的列表(单词出现在列表中的次数越多,选择的概率就越多)但我只能设法达到这个目的:

int numberOfWords=wordList.size(); //The Map
List<String> repeatedWords=new ArrayList<>();
for (Map.Entry<String,Integer> entry : wordList.entrySet()) {
    for (int i = 0; i < numberOfWords-entry.getValue(); i++) {
        repeatedWords.add(entry.getKey());
    }
}
Collections.shuffle(repeatedWords);  //Should it be get(Random)?
String chosenWord=repeatedWords.get(0);

我认为当选择的单词数量等于单词数量时,这会失败。

修改

最后,一旦他们有不同的数字,每个单词的概率就会出现问题。我已经改变了观点,所以我首先设置了1000的概率(可能是任何数字),每次我选择一个单词时,我减少一定数量的概率(比方说,20%),所以我使用:

wordList.put(chosen,(int)(wordList.get(chosen)*0.8)+1);

之后我选择Lajos Arpad或Ahmad Shahwan给出的食谱。 如果游戏要玩很多次,那么所有概率都倾向于1,但这不是我的情况。

感谢所有回答的人。

4 个答案:

答案 0 :(得分:0)

我不会提供准确的代码,但基本的想法。

  1. 迭代wordList.values()以找到最大权重M和权重总和S

  2. 现在让每个单词w都有可能(如概率,但不必总和为1)来选择M + 1 - wordList.get(w),所以一个单词的重量为{{} 1}}比具有权重1的单词更有可能被选择M倍。

  3. 可能性总和为M(这就是我们需要(M + 1) * wordList.size() - S的原因)。在0和此总和之间选择一个随机数S

  4. 迭代R,总结可能性。当总和通过wordList.entrySet()时,这就是你想要的单词。

答案 1 :(得分:0)

您的地图值是您的权重。

您需要选择一个低于权重总和的整数。

您可以选择每个String条目及其权重。当权重和通过随机整数时,你就在THE String。

这会给你:

public static void main(String ... args){
    Map<String, Integer> wordList = new HashMap<>();
    wordList.put("foo", 4);
    wordList.put("foo2", 2);
    wordList.put("foo3", 7);

    System.out.println(randomWithWeight(wordList));
}

public static String randomWithWeight(Map<String, Integer> weightedWordList) {
    int sum = weightedWordList.values().stream().collect(Collectors.summingInt(Integer::intValue));

    int random = new Random().nextInt(sum);
    int i = 0;
    for (Map.Entry<String, Integer> e : weightedWordList.entrySet()){
        i += e.getValue();
        if (i > random){
            return e.getKey();
        }
    }
    return null;
}

答案 2 :(得分:0)

试试这个:

import java.util.Map;
import java.util.HashMap;
import java.util.Random;

public class MyClass {
    public static void main(String args[]) {
        Map<String, Integer> wordList = new HashMap<>();
        wordList.put("alabanza", 3);
        wordList.put("esperanza", 4);
        wordList.put("comunal", 3);
        wordList.put("aprender", 1);

        Map<String, Integer> results = new HashMap<>(4);
        for (int i = 0; i < 100; i++) {
            String name = randomize(wordList);
            Integer old = results.getOrDefault(name, 0);
            results.put(name, old + 1);
        }

        for (Map.Entry<String, Integer> e : results.entrySet()) {
            System.out.println(e.getKey() + "\t" + e.getValue());
        }
    }

    private static String randomize(Map<String, Integer> wordList) {
        final Integer sum = wordList.values().stream().reduce(Integer::sum).orElse(0);
        final int grandSum = (wordList.size() - 1) * sum;
        final int random = new Random().nextInt(grandSum + 1);

        int index = 0;
        for (Map.Entry<String, Integer> e: wordList.entrySet()) {
            index += (sum - e.getValue());
            if (index >= random) {
                return e.getKey();
            }
        }
        return null;
    }
}

Out out是超过100次试验选择名称的时间:

aprender 37 alabanza 25 comunal 23 esperanza 15

您可以自己尝试here

答案 3 :(得分:0)

为简单起见,我们假设您有一个名为occurrences的数组,其中包含int个元素(您可以轻松将其转换为数据结构)。

现在,让我们找到最大值:

int max = 0;

for (int i = 0; i < occurrences.length; i++) {
    if (max < occurrences[i]) max = occurrences[i];
}

让它递增:

max++;

现在,让我们为{0}作为值的项目赋予max的权重,对于发生过一次的项目的权重max - 1,等等(没有项目将由于我们增加max),因此权重为0:

int totalWeight = 0;

for (int j = 0; j < occurrences.length; j++) {
    totalWeight += max - occurrences[j];
}

请注意,所有物品都有其重量。现在,让我们假设您有一个名为r的随机整数,其中 0&lt; r&lt; = totalWeight

int resultIndex = -1;

for (int k = 0; (resultIndex < 0) && k < occurrences.length; k++) {
    if (r <= max - occurrences[k]) resultIndex = k;
    else r -= max - occurrences[k];
}

,结果为occurrences[resultIndex]