Java 从Hashmap随机获取值

Java 从Hashmap随机获取值,java,Java,所以我有一个类型为的hashmap。它不是泛型类型 T是任意对象,整数是当前地图中该对象的数量 例如,一个字符串“shirt”,其值映射为3 我想构建一个名为random的方法,根据对象的当前分布从地图返回一个随机对象 也就是说,如果我的地图上有两个键,那就是“衬衫”和“裤子”。我的地图上有3件衬衫和7条裤子。分发的时间应为衬衫退回时间的30%,裤子退回时间的70% 我如何使用随机生成器执行类似的操作?地图数据类型使得实现您的需求变得非常困难。一个更好的数据结构将使它更容易。有各种可能的数据结构

所以我有一个类型为
的hashmap。它不是泛型类型

T是任意对象,整数是当前地图中该对象的数量

例如,一个字符串“shirt”,其值映射为3

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

也就是说,如果我的地图上有两个键,那就是“衬衫”和“裤子”。我的地图上有3件衬衫和7条裤子。分发的时间应为衬衫退回时间的30%,裤子退回时间的70%


我如何使用随机生成器执行类似的操作?

地图数据类型使得实现您的需求变得非常困难。一个更好的数据结构将使它更容易。有各种可能的数据结构可以优化不同的事物

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

换成一个简单的
列表如何

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

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);
如果地图包含(实际上)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");
}
private static T random basedonocurrence分布(Map){
SecureRandom=新的SecureRandom();
double total=map.values().stream().mapToInt(Integer::intValue.sum();
双骰子=random.nextDouble();
双层地板=0.0;
for(条目:map.entrySet()){
double currentProbability=entry.getValue()/total;
如果(骰子<地板+当前概率){
return entry.getKey();
}
楼层+=当前概率;
}
抛出新的RuntimeException(“不可访问”);
}
用法(摘自@Lukas answer):

Map Map=newhashmap();
地图放置(“衬衫”,3);
地图放置(“Pant”,7);
映射结果=新的HashMap();
对于(int i=0;i<100000;i++)
结果.计算(随机基发生率分布(map),
(s,j)->j==null?1:j+1);
系统输出打印项次(结果)//印花{裤子=69679,衬衫=30321}

请提供您目前拥有的源代码,好吗?你尝试过什么?是的,这是真的,但我的hashmap使用泛型类型。所以它不一定总是一个字符串。此外,HashMap可能具有多达100000个或更多对象的大小。所以制作一个数组(我以前就想到过)似乎效率很低。@Coder_Moler10345:好的,我修复了泛型部分。我将把答案留在这里,以防有人认为这种方法可以接受。我建议你更新你的问题,增加更多细节,否则你将无法得到你想要的答案如果两个项目的概率相同会发生什么…例如,我现在有5个项目衬衫=3,裤子=4,内衣=3,背心=1,袜子=6。在这种情况下,有两个项目的概率相同。那么,我如何确保这些物品的权重相同或被挑选的几率相同呢?@Coder_Moler10345如果两个物品的概率相同,那么他们被挑选的几率是相等的。您是否尝试使用更多项运行我的代码?
{Shirts=29955, Pants=70045}
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");
}
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}