随机获取数组中数据,连续获取不重复且不连续
随机获取数组中数据,连续获取不重复且不连续,应尽可能多次请求返回不一样数据。
关于讨论抽奖问题,做一个记录。
常用操作方式是使用Random的nextInt方法,获取随机数发放。但可能存在几点问题。(欢迎补充)
- 当数组中数据较少时,会多次返回相同数据,体验较差。
- 可能会存在连续两次返回相同数据,误以为并未随机展示。
- 奖品等级因根据级别不同,命中率应不相同。
常用办法解决以上问题(欢迎补充)
- 使用轮询方法
- 随机打乱并获取首位数据。
- 记录抽取与未抽取数据数据分别处理
当前处理方式
后续有其他方法再补充,当前仅记录简单思路,具体业务具体分析。
- 数据顺序不固定,且不连续
- Random
方法一:代码如下
@SpringBootTest
public class RandomTest {
private final CopyOnWriteArrayList<String> dataList = new CopyOnWriteArrayList<>();
private final CopyOnWriteArrayList<String> usedList = new CopyOnWriteArrayList<>();
public void addListAll(List<String> list) {
if (dataList.equals(list)) {
return;
}
dataList.clear();
dataList.addAll(list);
}
/**
* 获取
*/
public synchronized String getRandomElement() {
if (dataList.isEmpty()) {
// 如果列表中的元素已经用尽,可以选择重新填充或者返回空值
return null;
}
Collections.shuffle(dataList); // 随机打乱列表顺序
String element = dataList.remove(0); // 移除并返回第一个元素
usedList.add(element);
if (dataList.isEmpty()) {
// 如果列表中的元素已经用尽,将已使用的元素重新放回列表以实现循环使用
dataList.addAll(usedList);
usedList.clear();
}
return element;
}
@Test
public void testRandom() {
ArrayList<String> strings = new ArrayList<>() {{
add("foo");
add("bar");
add("baz");
add("boo");
}};
addListAll(strings);
for (int i = 0; i < 6; i++) {
String randomElement = getRandomElement();
System.out.println("randomElement:"+randomElement);
}
}
}
方法二:代码如下
@SpringBootTest
public class RandomTest {
private List<String> itemList;
private Set<String> drawnItems;
private Random random;
public RandomTest(List<String> itemList) {
this.itemList = new ArrayList<>(itemList);
this.drawnItems = new HashSet<>();
this.random = new Random();
}
public String drawItemForUser() {
if (itemList.isEmpty()) {
// 处理抽奖结束的逻辑,可以重新填充List或者采取其他处理方式
return "抽奖已结束";
}
String selectedItem = drawUniqueItem();
// 将抽取的元素添加到已抽取的集合中
drawnItems.add(selectedItem);
return selectedItem;
}
private String drawUniqueItem() {
int randomIndex = random.nextInt(itemList.size());
String selectedItem = itemList.get(randomIndex);
// 检查是否已经被抽取过
while (drawnItems.contains(selectedItem)) {
randomIndex = random.nextInt(itemList.size());
selectedItem = itemList.get(randomIndex);
}
return selectedItem;
}
public static void main(String[] args) {
List<String> items = new ArrayList<>();
items.add("奖品1");
items.add("奖品2");
items.add("奖品3");
items.add("奖品4");
items.add("奖品5");
items.add("奖品6");
items.add("奖品7");
RandomTest lottery = new RandomTest(items);
// 模拟一个用户连续抽取四次
for (int i = 1; i <= 10; i++) {
String result = lottery.drawItemForUser();
System.out.println("用户" + i + "抽到了:" + result);
}
}
}
加入彩票概率:代码如下
public class Lottery {
private List<String> itemList;
private Set<String> lastDrawnItems; // 用于记录上一次抽取的元素
private Random random;
public Lottery(List<String> itemList) {
this.itemList = new ArrayList<>(itemList);
this.lastDrawnItems = new HashSet<>();
this.random = new Random();
}
public String drawItemForUser() {
if (itemList.isEmpty()) {
// 处理抽奖结束的逻辑,可以重新填充List或者采取其他处理方式
return "抽奖已结束";
}
String selectedItem;
// 如果lastDrawnItems为空(第一次抽取)或者已经连续两次抽取相同元素,则重新抽取
do {
selectedItem = drawUniqueItem();
} while (lastDrawnItems.contains(selectedItem));
// 更新lastDrawnItems
lastDrawnItems.clear();
lastDrawnItems.add(selectedItem);
// 如果所有元素都已经被抽取,那么一等奖有可能被抽取
if (itemList.isEmpty()) {
// 这里可以根据需要调整一等奖的概率
if (random.nextDouble() < 0.1) { // 例如,10%的概率抽中一等奖
return "一等奖";
}
}
return selectedItem;
}
private String drawUniqueItem() {
int randomIndex = random.nextInt(itemList.size());
return itemList.remove(randomIndex);
}
public static void main(String[] args) {
List<String> items = new ArrayList<>();
items.add("奖品1");
items.add("奖品2");
items.add("奖品3");
items.add("奖品4");
Lottery lottery = new Lottery(items);
// 模拟一个用户连续抽取四次
for (int i = 1; i <= 6; i++) {
String result = lottery.drawItemForUser();
System.out.println("用户" + i + "抽到了:" + result);
}
}
}