随机获取Hashmap中的值

时间:2016-10-23 16:35:00

标签: java

所以我有一个<T,Integer>类型的哈希映射。 T是通用类型。

T是任意对象,整数是我们当前在地图中拥有的对象的数量。

例如,字符串“shirt”并且具有映射到它的值为3.

我想构建一个名为random的方法,它将根据对象的当前分布从地图中返回一个随机对象。

意思是,如果我的地图中有2个键......“衬衫”和“裤子”。我的地图上有3个“衬衫”和7个“裤子”。分配应该是返回衬衫的30%的时间,并且70%的时间将返回“裤子”。

我如何使用随机生成器做这样的事情?

2 个答案:

答案 0 :(得分:2)

该地图数据类型使您很难实现您的要求。更好的数据结构将使其变得更加容易。有各种可能的数据结构可以优化不同的东西。

解决几个不同的值/值计数

如果您需要经常选择随机值,并且如果您没有太多不同的值/值计数,那么这个解决方案非常有效:

简单的List<T>呢?

// Calculate this in advance
List<T> values = 
map.entrySet()
   .stream()
   .flatMap(entry -> Stream.generate(() -> entry.getKey())
                           .limit(entry.getValue()))
   .collect(Collectors.toList());

根据您的示例,此数组现在将包含3份"Shirts"和7份"Pants"

副本

现在很容易随机选择一个具有所需概率分布的值:

SecureRandom random = new SecureRandom();
T randomValue = values.get(random.nextInt(values.length));

证明:

Map<String, Integer> result = new HashMap<>();
for (int i = 0; i < 100000; i++)
    result.compute(values.get(random.nextInt(values.length)), 
                  (s, j) -> j == null ? 1 : j + 1);

System.out.println(result);

......收益率:

{Shirts=29955, Pants=70045}

答案 1 :(得分:0)

如果地图包含(虚拟)3件衬衫和7件裤子,则表示地图总共包含10个元素。

遇到衬衫的概率是3 /(7 + 3)= 0.3

遇到裤子的概率是7 /(7 + 3)= 0.7

现在,想象一下你可以掷骰子从0.0到1.0。如果骰子显示0.0到0.3之间的数字 - >挑一件衬衫。如果骰子显示0.3到1.0之间的数字 - >挑一条裤子。

以下代码实现了这个想法:

private static <T> T randomBasedOnOcurrenceDistribution(Map<T, Integer> map) {
    SecureRandom random = new SecureRandom();
    double total = map.values().stream().mapToInt(Integer::intValue).sum();
    double dice = random.nextDouble();
    double floor = 0.0;

    for (Entry<T, Integer> entry : map.entrySet()) {
        double currentProbability = entry.getValue() / total;
        if(dice < floor + currentProbability) {
            return entry.getKey();
        }
        floor += currentProbability;
    }
    throw new RuntimeException("Unreachable");
}

用法(复制自@Lukas答案):

Map<String, Integer> map = new HashMap<>();
map.put("Shirt", 3);
map.put("Pant", 7); 

Map<String, Integer> result = new HashMap<>();
for (int i = 0; i < 100000; i++)
       result.compute(randomBasedOnOcurrenceDistribution(map), 
                     (s, j) -> j == null ? 1 : j + 1);

System.out.println(result); //prints {Pant=69679, Shirt=30321}