1. 1. 随机项
    1. 1.1. 实现方式
    2. 1.2. 测试
      1. 1.2.1. 测试结果
  2. 2. 按照比例随机项
    1. 2.1. 实现
    2. 2.2. 测试
    3. 2.3. 测试结果

明月有圆缺,世事难完美。进新公司有三天了,又是一个没人带没培训也没有文档,直接给工程,然后分配任务开始干活,难道这个行业都是这样?还是我遇到的都是坑比公司呢!真心难说!直接上手做需求就做需求吧,确发现了系统中的很多的不健全和不人性化的东西,不知道一个面向互联网的应用这样会不会分分钟搞!老毛病又犯了!回归正题。

随机获取一个指定数组的元素和按照一定比例获取随机项这种功能在一定的在日常开发中肯定很常见。前者相对实现起来比较简单,但是后者网上有千奇百怪的而实现方式,而且其代码俩都相对较大,领人阅读的时候不能很愉快。当然每个人都有每个人的实现方式,凡是自己实现确实是不错的选择,至少是对自己的一种锻炼,当时同一个系统中到处都是这种实现类,而且一个类你写成千上上万行就好了,这就好比一袋真空的薯片,每每打开的时候总是领人停止流口水让人深深一谈。今天我就给出我的一种实现方式相对其他方式极大的简化了原理和实现方式。具体代码见github

随机项

实现方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 生成制定范围内的随机数
*
* @param scopeMin
* @param scoeMax
* @return
*/

public static int integer(int scopeMin, int scoeMax) {
Random random = new Random();
return (random.nextInt(scoeMax) % (scoeMax - scopeMin + 1) + scopeMin);
}
/**
* 从指定的数组中随机数组中的某个元素
*/

public static <T> T randomItem(T[] param) {
int index = integer(0, param.length);
return param[index];
}

测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Test
public void testRandomItem(){
for (int j = 0; j < 10; j++) {
Map<Integer,Integer> map = new HashMap();
for (int i = 0; i < 1000000; i++) {
Integer integer = RandomUtil.randomItem(new Integer[]{10, 30, 50});
if(map.containsKey(integer)){
map.put(integer,map.get(integer)+1);
}else{
map.put(integer,1);
}
}
int count = map.get(10)+map.get(30)+map.get(50);
String str = "10/30/50 ="+map.get(10)+":"+map.get(30)+":"+map.get(50)
+"("+count+")";
System.out.println(str);
}
}

测试结果

此处我随机了1000000次,下面是一些测试结果,从结果上来看相对还是比较靠谱

1
2
3
4
5
6
7
8
9
10
10/30/50 =333651:332493:333856(1000000)
10/30/50 =333098:333090:333812(1000000)
10/30/50 =333791:332406:333803(1000000)
10/30/50 =333052:333188:333760(1000000)
10/30/50 =333131:333132:333737(1000000)
10/30/50 =333920:333441:332639(1000000)
10/30/50 =332876:333978:333146(1000000)
10/30/50 =333948:332682:333370(1000000)
10/30/50 =333180:333794:333026(1000000)
10/30/50 =333030:333798:333172(1000000)

按照比例随机项

相对网络上的其他方式,此方法的实现原理很简单就随机一个数字,通过这个数字反映出其位置,然后通过位置即可保证随机比例,测试的时候发现随机的次数越多比例越接近设定的值。

实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/**
* 从指定的数组中按照指定比例返回指定的随机元素
* @param param
* @param percentum
* @param <T>
* @return
*/

public static <T> T randomItem(T[] param,double[] percentum){
int length = percentum.length;
Integer[] ints = ArrayUtil.doubleBitCount(percentum);
int max = Collections.max(Arrays.asList(ints));
int[] arr = new int[length];
int sum = 0;
Map map = new HashMap(length);
int multiple = Integer.parseInt("1"+strMultiplication("0",max));
for (int i = 0; i < length; i++) {
int temp = (int)(percentum[i] * multiple);
arr[i] = temp;
if(i == 0){
map.put(i,new int[]{1,temp});
}else{
map.put(i,new int[]{sum,sum+temp});
}
sum += temp;
}
int indexSum = integer(1,sum);
int index =-1;
for (int i = 0; i < length; i++) {
int[] scope = (int[]) map.get(i);
if(indexSum ==1 ){
index = 0;
break;
}
if(indexSum > scope[0] && indexSum <= scope[1]){
index =i;
break;
}
}
if(index == -1){
throw new RuntimeException("随机失败");
}else{
return param[index];
}
}

测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Test
public void testRandomItem1(){
for (int j = 0; j < 10; j++) {
Map<Integer,Integer> map = new HashMap();
for (int i = 0; i < 1000000; i++) {
double[] percentum = new double[]{0.6,0.3,0.1};
Integer integer = RandomUtil.randomItem(new Integer[]{10, 30, 50}, percentum);
if(map.containsKey(integer)){
map.put(integer,map.get(integer)+1);
}else{
map.put(integer,1);
}
}
int count = map.get(10)+map.get(30)+map.get(50);
String str = "10/30/50 ="+map.get(10)+":"+map.get(30)+":"+map.get(50)
+"("+count+")";
System.out.println(str);
}
}

测试结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//100的测试结果
10/30/50 =55:31:14(100)
10/30/50 =55:36:9(100)
10/30/50 =55:36:9(100)
10/30/50 =66:26:8(100)
10/30/50 =47:41:12(100)
10/30/50 =56:36:8(100)
10/30/50 =70:23:7(100)
10/30/50 =61:25:14(100)
10/30/50 =63:28:9(100)
10/30/50 =61:28:11(100)
//10000的测试结果
10/30/50 =5958:3015:1027(10000)
10/30/50 =6097:2932:971(10000)
10/30/50 =6060:2955:985(10000)
10/30/50 =6031:2985:984(10000)
10/30/50 =6056:2941:1003(10000)
10/30/50 =6005:3015:980(10000)
10/30/50 =6034:2982:984(10000)
10/30/50 =6113:2965:922(10000)
10/30/50 =6074:2941:985(10000)
10/30/50 =6009:3023:968(10000)
//1000000的测试结果
10/30/50 =600207:299855:99938(1000000)
10/30/50 =598348:301955:99697(1000000)
10/30/50 =599731:300340:99929(1000000)
10/30/50 =600493:298972:100535(1000000)
10/30/50 =599830:299970:100200(1000000)
10/30/50 =600513:299098:100389(1000000)
10/30/50 =600504:299652:99844(1000000)
10/30/50 =599420:300612:99968(1000000)
10/30/50 =600087:300101:99812(1000000)
10/30/50 =600047:300170:99783(1000000)