用.NET Core实现一个类似于饿了吗的简易拆红包功能
需求说明
以前很讨厌点外卖的我,最近中午经常点外卖,因为确实很方便,提前点好餐,算准时间,就可以在下班的时候吃上饭,然后省下的那些时间就可以在中午的时候多休息一下了。
点餐结束后,会有一个好友分享红包功能,虽说这个红包不能提现,但却可以抵扣点餐费用,对于经常点餐的人来说,直接用于抵扣现金确实是很大的诱惑,在点餐之后所获得的那个红包,必须要分享出去才能拆。
那么如果自己也想实现以下抢红包功能,需要说明的是,本文所描述的红包功能更多的关注与随机红包的生成,至于高并发、数据一致性等问题,本文暂未涉及,以下是本文所讨论的两个技术点:
- 不同的消费金额获取的红包总额不同,消费金额越大,红包总额就越大,红包总数也就越多;
- 假设有一天,有一种需求是,需要保证参与抢红包的人获得的红包金额在平均数附近波动,也就是尽量的服从正态分布;
功能实现
本文描述的场景,所涉及到的金额以分为单位,目的是为了更好的处理随机数。总体的示意图如下:
消费后红包的初始化
需求重点,用户分享出去的红包总额跟消费总额成正比,可以分拆的子红包个数也与消费总额成正比。
比如:
- 10-20元的消费金额,可以分享的单个红包金额为10元,可以供5个人抢
- 20-40元的消费金额,可以分享的单个红包金额为20元,可以供8个人抢
- 40-60元的消费金额,可以分享的单个红包金额为30元,可以供10个人抢
- 60-100元的消费金额,可以分享的单个红包金额为40元,可以供10个人抢
- 100元以上的消费金额,可以分享的单个红包金额为50元,可以供10个人抢
那么我们设计出来一个实体,用于表示红包信息,以方便的配置及调整红包规则
- 1: public class RedPacketsInfo
- 2: {
- 3: /// <summary>
- 4: /// 最大消费金额
- 5: /// </summary>
- 6: public int MaxAmount { get; set; }
- 7:
- 8: /// <summary>
- 9: /// 最小消费金额
- 10: /// </summary>
- 11: public int MinAmount { get; set; }
- 12:
- 13: /// <summary>
- 14: /// 红包金额
- 15: /// </summary>
- 16: public int TotalAmount { get; set; }
- 17:
- 18: /// <summary>
- 19: /// 红包可被分割的数量
- 20: /// </summary>
- 21: public int RedPacketQuantity { get; set; }
- 22: }
红包初始化信息
- 1: private static List<RedPacketsInfo> GetRedPackets()
- 2: {
- 3: return new List<RedPacketsInfo>()
- 4: {
- 5: new RedPacketsInfo
- 6: {
- 7: MinAmount = 1000,
- 8: MaxAmount = 2000,
- 9: RedPacketQuantity = 5,
- 10: TotalAmount=1000
- 11: },
- 12: new RedPacketsInfo
- 13: {
- 14: MinAmount = 2000,
- 15: MaxAmount = 3000,
- 16: RedPacketQuantity = 5,
- 17: TotalAmount=1000
- 18: },
- 19: new RedPacketsInfo
- 20: {
- 21: MinAmount = 4000,
- 22: MaxAmount = 6000,
- 23: RedPacketQuantity = 5,
- 24: TotalAmount=1000
- 25: },
- 26: new RedPacketsInfo
- 27: {
- 28: MinAmount = 6000,
- 29: MaxAmount = 8000,
- 30: RedPacketQuantity = 5,
- 31: TotalAmount=1000
- 32: },
- 33: new RedPacketsInfo
- 34: {
- 35: MinAmount = 10000,
- 36: MaxAmount = int.MaxValue,
- 37: RedPacketQuantity = 5,
- 38: TotalAmount=1000
- 39: }
- 40: };
- 41: }
接下来我们就可以通过消费金额获取相应的红包信息了。
随机红包的生成时机及处理
随机红包的生成可以在抢之前生成也可以在抢的过程中确定,一般而言,很多时候红包会在抢的过程中动态的实际分配,不过在本文中,红包在用户分享成功后会预先生成,主要原因是为了更好地处理处理数据,以使得数据能够服从正态分布。
以下是其流程图,其中有一段逻辑是回调功能,可能会有圈友会问,如何保证有回调以及回调是成功的,这个地方有很多种处理,比如MQ、任务调度等,此处也不做讨论
那么我们需要设计一个新的实体,以表示分享出去的红包及其生成的随机红包:
- 1: public class SharedRedPacket
- 2: {
- 3: /// <summary>
- 4: /// 分享人UserId
- 5: /// </summary>
- 6: public int SenderUserId { get; set; }
- 7:
- 8: /// <summary>
- 9: /// 分享时间
- 10: /// </summary>
- 11: public DateTime SendTime { get; set; }
- 12:
- 13: public List<RobbedRedPacket> RobbedRedPackets { get; set; }
- 14: }
- 15:
- 16: public class RobbedRedPacket
- 17: {
- 18: /// <summary>
- 19: /// 抢到红包的人的UserId
- 20: /// </summary>
- 21: public int UserId { get; set; }
- 22:
- 23: /// <summary>
- 24: /// 抢到的红包金额
- 25: /// </summary>
- 26: public int Amount { get; set; }
- 27:
- 28: /// <summary>
- 29: /// 抢到时间
- 30: /// </summary>
- 31: public DateTime RobbedTime { get; set; }
- 32: }
在实现过程中,根据用户消费金额获取相应红包,然后通过随机数,生成n-1个原始的随机数据,最后一个数据用总和减去n-1个数据的和获取到。
- 1: //红包随机拆分
- 2: Random ran = new Random();
- 3: List<double> randoms = new List<double>(redPacketsList.Count);
- 4: for (int i = 0; i < redPacketsInfo.RedPacketQuantity - 1; i++)
- 5: {
- 6: int max = (totalAmount - (redPacketsInfo.RedPacketQuantity - i)) * 1;
- 7: int result = ran.Next(1, max);
- 8: randoms.Add(result);
- 9: totalAmount -= result;
- 10: }
- 11: randoms.Add(totalAmount);
然后通过设置好系数,以处理数据达到服从正太分布的目的:
- 1: //正太分布处理
- 2: for (int i = 0; i < redPacketsInfo.RedPacketQuantity; i++)
- 3: {
- 4: double a = Math.Sqrt(Math.Abs(2 * Math.Log(randoms[i], Math.E)));
- 5: double b = Math.Cos(2 * Math.PI * randoms[i]);
- 6: randoms[i] = a * b * 0.3 + 1;
- 7: }
经过第二次处理后,得到的数据与原始数据有偏差,那么我们通过等比例方式再次处理,以确保拆分后的红包总额等于红包原始总额:
- 1: //生成最终的红包数据
- 2: double d = originalTotal / randoms.Sum();
- 3: SharedRedPacket sharedRedPacket = new SharedRedPacket();
- 4: sharedRedPacket.RobbedRedPackets = new List<RobbedRedPacket>(redPacketsList.Count);
- 5: for (int i = 0; i < redPacketsInfo.RedPacketQuantity - 1; i++)
- 6: {
- 7: sharedRedPacket.RobbedRedPackets.Add(new RobbedRedPacket
- 8: {
- 9: Amount = (int)Math.Round(randoms[i] * d, 0)
- 10: });
- 11: }
- 12: sharedRedPacket.RobbedRedPackets.Add(new RobbedRedPacket
- 13: {
- 14: Amount = originalTotal - sharedRedPacket.RobbedRedPackets.Sum(p => p.Amount)
- 15: });
测试
测试效果图如下:
部分代码如下,
- 1: Console.WriteLine("是否分享输入Y分享成功,输入N退出");
- 2: string result = Console.ReadLine();
- 3: if (result == "Y")
- 4: {
- 5: var leftRedPacket = sharedRedPacket.RobbedRedPackets.Where(p => p.UserId <= 0).ToList();
- 6: var robbedRedPacket = leftRedPacket[new Random().Next(1, leftRedPacket.Count + 1)];
- 7: Console.WriteLine("抢到的到红包金额是:" + robbedRedPacket.Amount);
- 8: Console.WriteLine("-------------------------------------------------------");
- 9: }
用.NET Core实现一个类似于饿了吗的简易拆红包功能的更多相关文章
- 【JavaScript框架封装】实现一个类似于JQuery的基础框架、事件框架、CSS框架、属性框架、内容框架、动画框架整体架构的搭建
/* * @Author: 我爱科技论坛 * @Time: 20180715 * @Desc: 实现一个类似于JQuery功能的框架 * V 1.0: 实现了基础框架.事件框架.CSS框架.属性框架. ...
- 使用ASP.NET Core MVC 和 Entity Framework Core 开发一个CRUD(增删改查)的应用程序
使用ASP.NET Core MVC 和 Entity Framework Core 开发一个CRUD(增删改查)的应用程序 不定时更新翻译系列,此系列更新毫无时间规律,文笔菜翻译菜求各位看官老爷们轻 ...
- windows forms 上一个类似于wpf snoop 的工具: Hawkeye
windows forms 上一个类似于wpf snoop 的工具: Hawkeye 周银辉 WPF上有snoop这样的run time object editor让人用着很爽, 今天搜到了一个for ...
- 分析一个类似于jquery的小框架
在网上下了一个类似于jQuery的小框架,分析源码,看看怎么写框架. 选择器Select //用沙箱闭包其整个代码,只有itcast和I暴漏在全局作用域 (function( window , und ...
- .NET Core跨平台:使用.NET Core开发一个初心源商城总括
1..NET Core基本介绍 a 作为一个.NET的开发者,在以前的开发中,我们开发的项目基本都是部署在windows服务器上,但是在windows服务器上的话某些比较流行的解决访问量的方案基本都是 ...
- 一个类似于jq的小型库
本人写了一个类似于jq的小型库,不过只是写了部分方法而已.并没有jq那么全面,下面就介绍下有哪些方法可以使用 第一个是选择器, 选择器比较简单 只支持ID选择器 $(‘#id_name’) Class ...
- 建立一个类似于天眼的Android应用程序:第4部分 - 持久收集联系人,通话记录和短信(SMS)
建立一个类似于天眼的Android应用程序:第4部分 - 持久收集联系人,通话记录和短信(SMS) 电话黑客android恶意软件编程黑客入侵linux 随着我们继续我们的系列,AMUNET应用程序变 ...
- python 写一个类似于top的监控脚本
最近老板给提出一个需要,项目需求大致如下: 1.用树莓派作为网关,底层接多个ZigBee传感节点,网关把ZigBee传感节点采集到的信息通过串口接收汇总,并且发送给上层的HTTP Serve ...
- 给 asp.net core 写一个简单的健康检查
给 asp.net core 写一个简单的健康检查 Intro 健康检查可以帮助我们知道应用的当前状态是不是处于良好状态,现在无论是 docker 还是 k8s 还是现在大多数的服务注册发现大多都提供 ...
随机推荐
- ASP.NET Core Razor 标签助手 - ASP.NET Core 基础教程 - 简单教程,简单编程
原文:ASP.NET Core Razor 标签助手 - ASP.NET Core 基础教程 - 简单教程,简单编程 ASP.NET Core Razor 标签助手 上一章节我们介绍了视图导入,学习了 ...
- nginx 502错 failed (13: Permission denied)
安装nginx和php-fpm之后出现502错误 找了个理由说php-fpm不启动 ,但在我的实践中,该过程开始 找了半天没找到病因.视图nginx记录后 我发现下面的错误 [crit] 2686#0 ...
- JS window下面的对象
) •Js脚本一执行就会访问服务器.超链接诶还需要点击. getElementById(), (非常常用),根据元素的Id获得对象,网页中id不能重复.也可以直接通过元素的id来引用元素,但是有有效范 ...
- WPF 数据模板DataType属性的使用,不用指定ItemTemplate
<Window x:Class="CollectionBinding.MainWindow" xmlns="http://schemas.micros ...
- laravel 报错SQLSTATE[HY000] [2002] No such file or directory
在mac中执行php artisan migrate时报错 SQLSTATE[HY000] [2002] No such file or directory (SQL: select * from i ...
- 从零开始学习音视频编程技术(三) 开发环境搭建(Qt4.86手动设置环境,主要就是设置g++和qmake,比较透彻,附下载链接)
1.先下载安装Qt 我们使用的版本是4.8. 可以自行百度下载也可以从下面的网盘地址下载: Qt库和编译器下载: 链接:http://pan.baidu.com/s/1hrUxLIG 密码:0181 ...
- PySide——Python图形化界面入门教程(二)
PySide——Python图形化界面入门教程(二) ——交互Widget和布局容器 ——Interactive Widgets and Layout Containers 翻译自:http://py ...
- ArcGIS 10.3 for Server 在windows下的安装教程
原文:ArcGIS 10.3 for Server 在windows下的安装教程 以下是10.2的教程,10.3同样适用. 许可文件: ArcGIS For Server10.3许可文件 - 下载频道 ...
- MessageBox用法大全
//1.显示提示信息 MessageBox.Show("Hello World!"); //2.给消息框加上标题 MessageBox.Show("Hello World ...
- 微信小程序把玩(二十一)switch组件
原文:微信小程序把玩(二十一)switch组件 switch开关组件使用主要属性: wxml <!--switch类型开关--> <view>switch类型开关</vi ...