Java 实现抽奖的两种方式

Java实现抽奖的两种方式

方式一:随机数在哪个区间内返回区间下标

方式二:随机数加入区间点集合排序返回随机数下标

代码示例:

①抽奖入参类型为BigDecimal:
package com.cfay;

import com.google.common.collect.Lists;
import org.apache.commons.collections4.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author lcb
 * @Date 2022/11/10
 **/
public class LuckDrawDemo {

    public static void main(String[] args) {
        List<BigDecimal> drawList = Lists.newArrayList();
        drawList.add(BigDecimal.valueOf(0.15));
        drawList.add(BigDecimal.valueOf(0.3));
        drawList.add(BigDecimal.valueOf(0.4));
        //抽奖测试
        List<Integer> luckDraws = Lists.newArrayList();
        for (int j = 0; j < 1000000; j++) {
            luckDraws.add(checkLuckDraw(drawList));
        }
        //按照数字进行分组排序
        Map<Integer, List<Integer>> luckDrawMap = luckDraws.stream().collect(Collectors.groupingBy(Integer::intValue));
        //遍历打印测试结果
        luckDrawMap.forEach((key, value) -> System.out.printf("第%s个出现的次数为:%d%n", key, value.size()));
    }

    /**
     * 抽奖检查
     *
     * @param drawList 抽奖列表
     * @return 抽中奖品下标
     */
    private static int checkLuckDraw(List<BigDecimal> drawList) {
        if (CollectionUtils.isEmpty(drawList)) {
            throw new RuntimeException("抽奖异常!");
        }
        if (CollectionUtils.isNotEmpty(drawList.stream().filter(Objects::isNull).collect(Collectors.toList()))) {
            throw new RuntimeException("抽奖异常!");
        }
        return luckDrawArea1(drawList);
    }

    /**
     * 抽奖1
     *
     * @param drawList 抽奖列表
     * @return 抽中奖品下标
     */
    private static int luckDrawArea1(List<BigDecimal> drawList) {
        //所有得到概率之和
        BigDecimal probability = drawList.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
        //多个抽奖区间
        List<List<BigDecimal>> draws = new ArrayList<>(drawList.size());
        BigDecimal initDraw = BigDecimal.ZERO;
        //抽奖区间
        List<BigDecimal> luckDraws;
        for (BigDecimal draw : drawList) {
            luckDraws = new ArrayList<>(2);
            //区间起点
            luckDraws.add(initDraw);
            //区间终点
            initDraw = initDraw.add(draw.divide(probability, 10, BigDecimal.ROUND_HALF_UP));
            luckDraws.add(initDraw);
            draws.add(luckDraws);
        }
        BigDecimal random = BigDecimal.valueOf(Math.random());
        //过滤出抽奖区间的位置
        return draws.indexOf(draws.stream().filter(draw ->
                draw.get(0).compareTo(random) <= 0 && draw.get(1).compareTo(random) > 0).findAny().orElseGet(ArrayList::new)) + 1;
    }

    /**
     * 抽奖2
     *
     * @param drawList 抽奖列表
     * @return 抽中奖品下标
     */
    private static int luckDrawArea2(List<BigDecimal> drawList) {
        //所有得到概率之和
        BigDecimal probability = drawList.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
        //多个抽奖点
        List<BigDecimal> draws = new ArrayList<>(drawList.size() + 1);
        //抽奖点
        BigDecimal initDraws = BigDecimal.ZERO;
        for (BigDecimal draw : drawList) {
            initDraws = initDraws.add(draw.divide(probability, 10, BigDecimal.ROUND_HALF_UP));
            draws.add(initDraws);
        }
        //放入随机抽奖区间,并返回抽检区间的下标
        BigDecimal random = BigDecimal.valueOf(Math.random());
        draws.add(random);
        Collections.sort(draws);
        return draws.indexOf(random) + 1;
    }
}

②、抽奖入参类型为Double
package com.cfay;

import com.google.common.collect.Lists;
import org.apache.commons.collections4.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author lcb
 * @Date 2022/11/10
 **/
public class LuckDrawDemo2 {

    public static void main(String[] args) {
        List<Double> drawList = Lists.newArrayList();
        drawList.add(0.15d);
        drawList.add(0.3d);
        drawList.add(0.4d);
        //抽奖测试
        List<Integer> luckDraws = Lists.newArrayList();
        for (int j = 0; j < 1000000; j++) {
            luckDraws.add(checkLuckDraw(drawList));
        }
        //按照数字进行分组排序
        Map<Integer, List<Integer>> luckDrawMap = luckDraws.stream().collect(Collectors.groupingBy(Integer::intValue));
        //遍历打印测试结果
        luckDrawMap.forEach((key, value) -> System.out.printf("第%s个出现的次数为:%d%n", key, value.size()));
    }

    /**
     * 抽奖检查
     *
     * @param drawList 抽奖列表
     * @return 抽中奖品下标
     */
    private static int checkLuckDraw(List<Double> drawList) {
        if (CollectionUtils.isEmpty(drawList)) {
            throw new RuntimeException("抽奖异常!");
        }
        if (CollectionUtils.isNotEmpty(drawList.stream().filter(Objects::isNull).collect(Collectors.toList()))) {
            throw new RuntimeException("抽奖异常!");
        }
        if (drawList.stream().reduce(Double::sum).orElse(0d) == 0d) {
            throw new RuntimeException("抽奖异常!");
        }
        return luckDrawArea2(drawList);
    }

    /**
     * 抽奖1
     *
     * @param drawList 抽奖列表
     * @return 抽中奖品下标
     */
    private static int luckDrawArea1(List<Double> drawList) {
        //所有得到概率之和
        Double probability = drawList.stream().reduce(Double::sum).orElse(0d);
        //多个抽奖区间
        List<List<Double>> draws = new ArrayList<>(drawList.size());
        double initDraw = 0d;
        //抽奖区间
        List<Double> luckDraws;
        for (Double draw : drawList) {
            luckDraws = new ArrayList<>(2);
            //区间起点
            luckDraws.add(initDraw);
            //区间终点
            luckDraws.add(initDraw += draw / probability);
            draws.add(luckDraws);
        }
        Double random = Math.random();
        //过滤出抽奖区间的位置
        return draws.indexOf(draws.stream().filter(draw ->
                draw.get(0).compareTo(random) <= 0 && draw.get(1).compareTo(random) > 0).findAny().orElseGet(ArrayList::new)) + 1;
    }

    /**
     * 抽奖2
     *
     * @param drawList 抽奖列表
     * @return 抽中奖品下标
     */
    private static int luckDrawArea2(List<Double> drawList) {
        //所有得到概率之和
        Double probability = drawList.stream().reduce(Double::sum).orElse(0d);
        //多个抽奖点
        List<Double> draws = new ArrayList<>(drawList.size() + 1);
        //抽奖点
        double initDraws = 0d;
        for (Double draw : drawList) {
            draws.add(initDraws += draw / probability);
        }
        //放入随机抽奖区间,并返回抽检区间的下标
        Double random = Math.random();
        draws.add(random);
        Collections.sort(draws);
        return draws.indexOf(random) + 1;
    }
}

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Java Redis抽奖是一种基于Java编程语言和Redis数据库技术实现抽奖系统。下面将从设计思路、实现方式和功能特点三个方面来回答。 首先,设计思路。Java Redis抽奖系统的设计思路主要包括两个方面:抽奖逻辑和数据存储。抽奖逻辑部分,我们可以通过随机数生成算法来确定中奖者,根据不同的抽奖规则来确定奖品分配方案。数据存储部分,我们使用Redis数据库来进行数据存储,可以使用Hash类型来保存抽奖活动的信息,使用Set类型来保存参与抽奖的用户信息。 其次,实现方式Java Redis抽奖系统的实现方式主要涉及Java编程语言和Redis数据库的调用。在Java方面,我们可以使用Java的Redis客户端工具来连接Redis数据库,通过执行相应的命令来操作Redis中的数据。在Redis方面,我们可以使用Redis的数据结构来存储和处理抽奖相关的数据,例如使用Hash类型来存储抽奖活动的信息,使用Set类型来存储参与抽奖的用户信息。 最后,功能特点。Java Redis抽奖系统具有以下几个功能特点:高效性、可扩展性和即时性。由于Redis是基于内存的数据库,具有读写速度快的特点,因此Java Redis抽奖系统可以实现高效的抽奖过程。同时,Redis支持集群模式和分布式部署,因此Java Redis抽奖系统可以实现可扩展性,可以应对大量用户同时参与抽奖的情况。此外,由于Redis支持发布订阅机制,Java Redis抽奖系统可以实现即时性,在抽奖结果产生时可以实时通知参与者,提升用户体验。 综上所述,Java Redis抽奖系统是一种基于Java编程语言和Redis数据库技术实现抽奖系统,具有高效性、可扩展性和即时性的特点。通过合理的设计思路和实现方式,可以满足用户对抽奖系统的需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

楚风岸影

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值