根据数据的权重,随机返回一个数据

发布时间 2023-07-05 17:39:31作者: 平平无奇刘彦祖
/**
 * 根据权重,随机取出值
 * @param dataWeightMap 数据-权重 的映射
 * @param <T> 数据类型
 * @return 根据权重随机的数据
 */
public static <T> T randomWeight(Map<T, Integer> dataWeightMap){
   // <数据, int[min, max]> 计算是否属于此范围时:前包后不包
   Map<T, int[]> rangeMapper = new HashMap<>();

   int count=0;
   for(T data : dataWeightMap.keySet()){
      // 初始化权重
      Integer weight = dataWeightMap.get(data);
      weight = weight == null ? 1 : weight;
      if(weight < 1) {
         continue;
      }
      // 初始化范围
      int[] range = new int[2];
      rangeMapper.put(data, range);
      
      // 计算随机范围
      range[0] = count;
      count += weight;
      range[1] = count;
   }
   // 生成随机数,并判断符合权重范围(前包后不包)的数据
   int randNum = (int) (Math.random() * count);
   for(T data : rangeMapper.keySet()){
      int[] range = rangeMapper.get(data);
      if(randNum >= range[0] && randNum < range[1]) {
         return data;
      }
   }
   return null;
}

测试:

/**
* 权重随机返回测试
* @param args
*/
public static void main(String[] args) {
Map<String, Integer> dataWeightMap = new HashMap<>();
dataWeightMap.put("A", 2);
dataWeightMap.put("B", 1);
dataWeightMap.put("C", 2);
dataWeightMap.put("D", 1);

Map<String, Integer> countMap = new HashMap<>();
dataWeightMap.forEach((k, v) -> countMap.put(k, 0));

int num = 1000000;
for(int i=0; i< num; i ++) {
String res = randomWeight(dataWeightMap);
countMap.compute(res, (k, v) -> v + 1);
}

countMap.forEach((k, v) -> System.out.println(k+":"+v));
}
 

结果:

A:332530
B:166882
C:333462
D:167126

====================

A:332845
B:167135
C:333458
D:166562

可自行修改参数,反复测试