从list中取N个随机生成一个集合
在工作中发现有很多有序算法,较少见到一些可用的无序随机算法。无序随机算法的目的是让客户感觉每次都不一样,因为一直看一样的会审美疲劳哈。
在jdk自带一种CollectionUtils.shuffle<List<?> list> 使用默认随机源对指定列表进行置换,方便快捷。熟读JDK是如此的重要。
一下两种算法适用于一些特殊场合
特意写了两种算法。一种是利用set集合的特性,加上优化,因为如果list的个数不大,要在list中取的个数比较多的情况下,采用逆向生成算法,最佳适用于大数据量选取少量随机元素。
另外一种是随机置换位置法,每一个位置都有一次换位的机会,最佳适用于小数据量选取大量随机元素。
有好的意见可以分享给我哈。
package com.duotin.japi.common.utils; import com.duotin.util.CollectionUtils;
import org.apache.commons.lang.math.RandomUtils; import java.util.*; /**
* 生成随机集合工具类
*
*/
public class RandomDataUtil {
public final static int TWO=2;
/**
* 生成随机集合(不重复)
* <p>
* 使用Set的值唯一的特性。
* 最佳适用场合:集合中数目多,取相对较少对象时。在取对象相对较多时(超过集合的一半时)采用逆向方法,
* 在取得对象个数是集合总数的1/2左右时是效率最慢的。
* </p>
* @param list
* @param generateNum 生成集合中元素的个数
* @param <T>
* @return
*/
public <T> List<T> generateRandomDataNoRepeat(List<T> list,Integer generateNum){
List<T> tList = new ArrayList<T>();
if(CollectionUtils.isNotEmpty(list)) {
for (Integer num : generateRandomNoRepeat(list.size(), generateNum)) {
tList.add(list.get(num));
}
}
return tList;
} /**
* 生成随机集合,随机置换位置、随机截取位置法。
* <p>
* 随机置换法:将集合的每个位置值与随机位置的值调换,并随机截取位置.
* 最佳适合场合:集合的数量相对较少,获取较多的随机个数集合。
* </p>
* @param list
* @param generateNum
* @param <T>
* @return
*/
public <T> List<T> generateRandomPermutation(List<T> list,Integer generateNum){
if(CollectionUtils.isNotEmpty(list)) {
checkParams(list.size(),generateNum);
List<T> randomAllList = randomPermutation(list, generateNum);
int initPosition=interceptPosition(list.size(),generateNum);
return randomAllList.subList(initPosition,initPosition+generateNum);
}
return Collections.emptyList();
} /**
* 随机置换算法
* @param list
* @param generateNum
* @param <T>
* @return
*/
private <T> List<T> randomPermutation(List<T> list,Integer generateNum){
for (int i = 0; i < list.size(); i++) {
Integer random=RandomUtils.nextInt(list.size());
T t = list.get(random);
list.set(random,list.get(i));
list.set(i,t);
}
return list;
} /**
* 随机生成截取位置
* @param totalCount
* @param generateNum
* @return
*/
private Integer interceptPosition(Integer totalCount,Integer generateNum){
int num=RandomUtils.nextInt(totalCount);
if(num+generateNum>totalCount){
num=num-generateNum;
}
return num;
}
/**
* 生成不重复的随机数
* @param totalCount
* @param generateNum
* @param
* @return
*/
public Set<Integer> generateRandomNoRepeat(Integer totalCount,Integer generateNum){
if(isLessThanHalfTotalCount(totalCount,generateNum)){
return getRandomNoRepeat(totalCount,generateNum);
}
return getReverseRandomNoRepeat(totalCount,generateNum);
} /**
* 验证参数是否合法
* @param totalCount
* @param generateNum
*/
private void checkParams(Integer totalCount,Integer generateNum){
if(totalCount<generateNum){
throw new IllegalArgumentException("generateNum is out of totalCount");
}
} /**
* 判断使用哪种生成机制
* @param totalCount
* @param generateNum
* @return
*/
private Boolean isLessThanHalfTotalCount(Integer totalCount,Integer generateNum){
if(generateNum<totalCount/TWO){
return Boolean.TRUE;
}
return Boolean.FALSE;
} /**
* 生成set,不重复
* @param totalCount
* @param generateNum
* @return
*/
private Set<Integer> getRandomNoRepeat(Integer totalCount,Integer generateNum){
Set<Integer> set = new HashSet<Integer>();
while (true) {
set.add(RandomUtils.nextInt(totalCount));
if(set.size() == generateNum){
return set;
}
}
} /**
* 逆向生成set,不重复
* @param totalCount
* @param generateNum
* @return
*/
private Set<Integer> getReverseRandomNoRepeat(Integer totalCount,Integer generateNum){
Set<Integer> set = new HashSet<Integer>();
while (true) {
set.add(RandomUtils.nextInt(totalCount));
if(set.size() == totalCount-generateNum){
Set<Integer> setALL=getSetALL(totalCount);
setALL.removeAll(set);
return setALL;
}
}
} /**
* 生成Set
* @param totalCount
* @return
*/
private Set<Integer> getSetALL(Integer totalCount){
Set<Integer> set = new HashSet<Integer>();
for(int i=0;i<totalCount;i++){
set.add(i);
}
return set;
} }
从list中取N个随机生成一个集合的更多相关文章
- PYTHON练习题 二. 使用random中的randint函数随机生成一个1~100之间的预设整数让用户键盘输入所猜的数。
Python 练习 标签: Python Python练习题 Python知识点 二. 使用random中的randint函数随机生成一个1~100之间的预设整数让用户键盘输入所猜的数,如果大于预设的 ...
- 转:在0~N(不包括N)范围内随机生成一个长度为M(M <= N)且内容不重复的数组
1. 最朴素暴力的做法. void cal1() { , j = , num = ; int result[M]; result[] = rand() % N; //第一个肯定不重复, 直接加进去 ; ...
- JAVA代码:生成一个集合,自定义大小,100以内的随机整数
JAVA代码:生成一个集合,自定义大小,100以内的随机整数 方法一:(Random类) package com.dawa.test; import java.util.ArrayList; impo ...
- (爬虫)随机生成一个header
#!/usr/bin/env python #-*- coding: utf-8 -*- #__Author__: yunrui #__Version__: 1.0 #__Time__: 2019/1 ...
- python接口自动化中,注册接口随机生成手机号码
如大家所知在注册接口中,手机号参数需要的是未注册的手机号,而在测试用例中,你写入的手机号不一定是未注册的.所以这时需要对注册接口中传入的手机号做处理.下面我就分享一个课程里面学到的一个处理手机号的py ...
- js随机生成一个数组中的随机字符串以及更新验证码
随机生成m,n范围的值得公式: Math.random()*(n-m)+m: 改正公式:Math.random()*(n+1-m)+m // 生成随机字符串function randomMixed(n ...
- 随机获取一个集合(List, Set)中的元素,随机获取一个Map中的key或value
利用Java提供的Random类.从List或Set中随机取出一个元素,从Map中随机获取一个key或value. 因为Set没有提供get(int index)方法,仅仅能先获取一个随机数后.利用一 ...
- 随机获取一个集合(List, Set,Map)中的元素<转>
import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Random; impo ...
- JS中取整以及随机颜色问题
前言:感觉自己已经好久好久没有写博客了,最近都是在写在线笔记比较多.现在来到新公司了,昨天刚刚完成一个项目所以今天有空研究研究一下前端方面的技术.下午在看一个游戏代码的时候,发现了几个别人留下的不错的 ...
随机推荐
- C# 添加Log文件、记录Log
其实在平时的开发过程中都是不怎么写log的,觉得在debug中能看得一清二楚.同事小姐姐前辈,一直就我不写log进行批判,但是我从来不改,哈哈.也算是遇到报应了,在最近一个工程里,本地调试一切正常,到 ...
- SASS - 函数
SASS – 简介 SASS – 环境搭建 SASS – 使用Sass程序 SASS – 语法 SASS – 变量 SASS- 局部文件(Partial) SASS – 混合(Mixin) SASS ...
- spring boot redis 缓存(cache)集成
Spring Boot 集成教程 Spring Boot 介绍 Spring Boot 开发环境搭建(Eclipse) Spring Boot Hello World (restful接口)例子 sp ...
- CF1217A Creating a Character
You play your favourite game yet another time. You chose the character you didn't play before. It ha ...
- 寒假day19
今天编写了人才动态模块,同时刷了一些算法题.
- POJ 1519:Digital Roots
Digital Roots Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 25766 Accepted: 8621 De ...
- MySql 的操作指令(window)
1.登录: mysql -uroot -p 2.查看所有数据库: show databases 3.切换数据库 : use databasename(数据库名称) 4.查看数据库的所有表格 ...
- Windows安装使用SonarQube7.4 对java项目进行代码质量扫描
我这里使用7.4因为使用JDK是1.8 其它版本看下依赖版本就好 1.下载7.4版本安装包 https://binaries.sonarsource.com/CommercialDistributio ...
- bootstrap 网格
实现原理 网格系统的实现原理非常简单,仅仅是通过定义容器大小,平分12份(也有平分成24份或32份,但12份是最常见的),再调整内外边距,最后结合媒体查询,就制作出了强大的响应式网格系统.Bootst ...
- TCP三次握手和四次挥手相关
客户端A 服务端BSYN (建立连接位标识 1为建立联机) ACK (确认位标识 1为确认) seq (一个随机顺序码) ack(一个确认号码,通常为seq+1) 三次握手:1.A 发起建立 连接 的 ...