zoukankan      html  css  js  c++  java
  • 相同概率的抽奖程序另类实现——使用数据库,无需数学原理

      抽奖,是很多企业、聚会的常见玩乐形式,光彩绚丽的抽奖屏幕背后,是计算程序+抽奖用户信息。程序=算法+数据结构。

    好,说抽奖程序的的实现吧。这个实现一般需要应用数学原理。而本文的方法是我在参加一次婚礼的抽奖体验后突然想到的,一种比较简单、无需数学原理的方法。

    功能:能按照相同概率,从用户集合中抽出随机的部分用户集合作为中奖者。抽奖可以进行多次,对已中奖的用户不会重复抽取。

      使用技术:

    1.SqlServer数据库,使用NewID()作为select随机筛选函数

    2.sql随机函数

    3.为了快速方便的搭建原型,使用EF 4.1 DB first,然后代码生成Model类(我在快速开发原型是喜欢EF,讨厌sql-实体转换。能让我从sql中解放出来,专注业务逻辑。只有

    当需要的sql逻辑比较复杂,EF难以实现或效率不行时我才写sql-实体转换)。

      主要逻辑:

    1.建立LotteryUsers(抽奖用户的英文词组)表,定义用户信息、以及是否已中过奖的标志位IsLotteried,默认都是false-0(IsDelete-该用户是否已删除、无效)。

    2.执行sql查询出定量的中奖用户集合 :

    SELECT TOP(@chooseCount) * FROM LotteryUsers lu WHERE lu.IsDeldte = 0 AND lu.IsLotteried = 0  ORDER BY NEWID()

    并且将这些中奖用户的IsLotteried字段设置为true-1

    3.控制台显示中奖的用户集合

    DB建表语句:

     1 CREATE TABLE [dbo].[LotteryUsers](
     2     [Id] [int] IDENTITY(1,1) NOT NULL,
     3     [JobNumber] [nvarchar](50) COLLATE Chinese_PRC_CI_AS NOT NULL,
     4     [Name] [nvarchar](50) COLLATE Chinese_PRC_CI_AS NOT NULL,
     5     [IsLotteried] [bit] NOT NULL,
     6     [IsDeldte] [bit] NOT NULL,
     7  CONSTRAINT [PK_LotteryUsers] PRIMARY KEY CLUSTERED 
     8 (
     9     [Id] ASC
    10 )
    View Code

    结构、示例数据:

    程序结构:

    代码(使用EF 4.1,实体生成模型),代码细节、EF技术看不懂没关系,了解原理即可:

     1 static void Main(string[] args)
     2         {
     3             //添加测试数据:用户信息
     4             ////using (LotteryContext context = new LotteryContext())
     5             ////{
     6             //    for (int i = 1; i < 101; i++)
     7             //    {
     8             //        LotteryUser user = new LotteryUser
     9             //        {
    10             //            JobNumber = i.ToString("00000"),
    11             //            Name = "niu"+i.ToString(),
    12             //            IsLotteried = false,
    13             //            IsDeldte = false,
    14             //        };
    15             //        context.LotteryUsers.Add(user);
    16             //    }
    17             //    context.SaveChanges();
    18             //}
    19 
    20             //从用户集合中随机抽取部分中奖用户显示
    21             var lotteryUsers = GetPrizeUsersAndUpdatePrized(10);
    22             foreach (var lotteryUser in lotteryUsers)
    23             {
    24                 Console.WriteLine(string.Join(",", lotteryUser.Id, lotteryUser.JobNumber, lotteryUser.Name));
    25             }
    26 
    27         }
    28 
    29         /// <summary>
    30         /// 从用户集合中随机抽取部分中奖用户,并将这些用户更新为已中奖、下次不会重复中奖
    31         /// </summary>
    32         /// <param name="chooseCount">指定中奖用户个数</param>
    33         public static List<LotteryUser> GetPrizeUsersAndUpdatePrized(int chooseCount)
    34         {
    35             List<LotteryUser> lotteryUsers = new List<LotteryUser>();
    36             using (LotteryContext context = new LotteryContext())
    37             {
    38 
    39                 string lotteryUsersSql = @"SELECT TOP(@chooseCount) * FROM LotteryUsers lu 
    40                                         WHERE lu.IsDeldte = 0 AND lu.IsLotteried = 0 
    41                                         ORDER BY NEWID()";
    42                 lotteryUsers = context.LotteryUsers.SqlQuery(lotteryUsersSql
    43                     , new SqlParameter("@chooseCount", chooseCount)).ToList();
    44                 //foreach (var lotteryUser in lotteryUsers)
    45                 //{
    46                 //    Console.WriteLine(string.Join(",", lotteryUser.Id, lotteryUser.JobNumber, lotteryUser.Name, lotteryUser.IsLotteried, lotteryUser.IsDeldte));
    47                 //}
    48                 
    49                 //更新已得过奖状态为:是
    50                 foreach (var lotteryUser in lotteryUsers)
    51                 {
    52                     lotteryUser.IsLotteried = true;
    53                 }
    54                 context.SaveChanges();
    55 
    56                 return lotteryUsers;
    57             }
    58         }
    View Code

    就这样,lotteryUsers即是中奖的用户。若要继续抽奖,只要再调用GetPrizeUsersAndUpdatePrized()即可,中奖用户不会重复。

    ---------------------------------------------备注、其他----------------

    1.对于某些抽奖,若要内定某些VIP中某个奖,最好不要写死、在配置文件中写上VIP的名字,在抽奖函数中传入这些VIP的名单、直接确认。

    2.对于某些次VIP们,若需要提高中奖概率,需要待议。可能实现的方法有:在users表中加上权重Pritory值,然后再做某些操作;或者采用其他较复杂的数学实现方法。

    3.我的程序不注重程序DB效率,所以未经优化。但是实际上,一般抽奖用户也就1W人以下,完全不存在性能问题。(中国16亿人全名抽奖,淘宝京东等全站抽奖数据量很大的,需要另行优化)。

  • 相关阅读:
    你的系统需要做系统集成测试么?
    测试驱动 ASP.NET MVC 和构建可测试 ASP.NET MVC 应用程序
    RikMigrations 或 Migrator.NET 进行自动化的数据库升级
    单元测试
    C#反射
    J2EE--Struts2基础开发
    Dynamics CRM 客户端的插件调试
    于快速创建 IEqualityComparer<T> 实例的类 Equality<T>
    ToolBox Analysis & Design
    实现$.fn.extend 和$.extend函数
  • 原文地址:https://www.cnblogs.com/nlh774/p/4857333.html
Copyright © 2011-2022 走看看