根据权重随机选取指定条数记录的简单算法实现(C#)

   2023-02-09 学习力0
核心提示:一.应用场景:有时我们需要从一些列数据中根据权重随机选取指定条数记录出来,这里需要权重、随机,我们根据权重越大的,出现概率越大。例如广告系统:可根据客户支付金额大小来调控客户们的广告出现概率,客户支付金额越大,其广告出现频率越频繁,例如:加


一.应用场景:

有时我们需要从一些列数据中根据权重随机选取指定条数记录出来,这里需要权重、随机,我们根据权重越大的,出现概率越大。例如广告系统:可根据客户支付金额大小来调控客户们的广告出现概率,客户支付金额越大,其广告出现频率越频繁,例如:加入有10条广告,然后每条广告都有一个权重,我们每次要根据权重选取5条广告出来进行显示。有了需求,我们就进行解决,本文章就是利用一种简单的算法来实现根据权重来随机选取。

二.简单算法的实现:

   根据我们需求,上网找了不少资料,都没有找到一种比较适合的方案,就自己想了一个简单的实现方案,试了一下,效果还挺不错的,现在和大家分享分享,有不合理或者错误之处,还望各位高手纠正。废话少说,其实算法很简单,如下:

  1. 每个广告都有一个权重,用W表示。我们假设最小的权重为1,数字越大的权重越高。
  2. 计算出所有广告的权重总和,用SUM表示。
  3. 遍历每个广告,将它的权重W与从0到(SUM-1)的一个随机数(即权重总和SUM以内的随机数)相加,得到新的权重排序值,用S表示。
  4. 根据广告权重排序值S从大到小进行排序。
  5. 根据排序结果选取最前面的几条记录就是我们所需要的结果。

其简单原理如下:

1.假如我们有A、B、C、D四个广告,其权重分别为1、2、3、4,则其总权重SUM=1+2+3+4=10。

2.根据其权重值与一个小于SUM的随机值(由于SUM=10,则随机值范围是0~9)相加,得到一个权重排序值,如下:

广告
权重值
最小权重排序值
最大权重排序值

A
1
1+0=1
1+9=10

B
2
2+0=2
2+9=11

C
3
3+0=3
3+9=12

D
4
4+0=4
4+9=13

3.由此可以得出A、B、C、D的范围,由上面可以看出A是1~10之间的数,而D的范围是4~13,由此可以看出,D得出随机数大的概率比较大。所以我们只要根据其出现概率再排一下顺序,再选取排在权重排序值比较大的前几项即可,这就可以得到我们所需要的根据权重选取概率的广告。

三.C#代码算法的实现:

1.首先我们先声明一个权重基础类RandomObject,以后只要继承该类即可。其代码如下:

根据权重随机选取指定条数记录的简单算法实现(C#)

/// <summary>
/// 权重对象
/// </summary>
public class RandomObject
{
/// <summary>
/// 权重
/// </summary>
public int Weight { set; get; }
}

根据权重随机选取指定条数记录的简单算法实现(C#)

这个类我们只定义一个Weight属性,其它属性可由继承它的类根据具体业务来实现具体属性。

2.创建一个辅助类RandomHelper,新增一个实现根据权重随机选取条数的的函数,其代码如下:

根据权重随机选取指定条数记录的简单算法实现(C#)

    /// <summary>
/// 算法:
/// 1.每个广告项权重+1命名为w,防止为0情况。
/// 2.计算出总权重n。
/// 3.每个广告项权重w加上从0到(n-1)的一个随机数(即总权重以内的随机数),得到新的权重排序值s。
/// 4.根据得到新的权重排序值s进行排序,取前面s最大几个。
/// </summary>
/// <param name="list">原始列表</param>
/// <param name="count">随机抽取条数</param>
/// <returns></returns>
public static List<T> GetRandomList<T>(List<T> list, int count) where T: RandomObject
{
if (list == null || list.Count <= count || count <= 0)
{
return list;
}

//计算权重总和
int totalWeights = 0;
for (int i = 0; i < list.Count; i++)
{
totalWeights += list[i].Weight + 1; //权重+1,防止为0情况。
}

//随机赋值权重
Random ran = new Random(GetRandomSeed()); //GetRandomSeed()随机种子,防止快速频繁调用导致随机一样的问题
List<KeyValuePair<int, int>> wlist = new List<KeyValuePair<int, int>>(); //第一个int为list下标索引、第一个int为权重排序值
for (int i = 0; i < list.Count; i++)
{
int w = (list[i].Weight + 1) + ran.Next(0, totalWeights); // (权重+1) + 从0到(总权重-1)的随机数
wlist.Add(new KeyValuePair<int, int>(i, w));
}

//排序
wlist.Sort(
delegate(KeyValuePair<int, int> kvp1, KeyValuePair<int, int> kvp2)
{
return kvp2.Value - kvp1.Value;
});

//根据实际情况取排在最前面的几个
List<T> newList = new List<T>();
for (int i = 0; i < count; i++)
{
T entiy = list[wlist[i].Key];
newList.Add(entiy);
}

//随机法则
return newList;
}

根据权重随机选取指定条数记录的简单算法实现(C#)

为了适合各个场景,我们定义T是一个泛型类,该类务必继承RandomObject类,实现自己类信息。该方法有相关的注释,这里就不再详细重复描述。

特别注意一下GetRandomSeed()这个函数,这个是为了防止在短时间内频繁创建和调用Random时候,会出现重复的随机数(也就是随机不在是随机的问题),其函数代码如下:

根据权重随机选取指定条数记录的简单算法实现(C#)

    /// <summary>
/// 随机种子值
/// </summary>
/// <returns></returns>
private static int GetRandomSeed()
{
byte[] bytes = new byte[4];
System.Security.Cryptography.RNGCryptoServiceProvider rng = new System.Security.Cryptography.RNGCryptoServiceProvider();
rng.GetBytes(bytes);
return BitConverter.ToInt32(bytes, 0);
}

根据权重随机选取指定条数记录的简单算法实现(C#)

3.调用方法:

调用方法很简单,只需要声明一个自己的实体,集成Object,然后根据实际情况直接调用RandomHelper.GetRandomList()方法即可。

如下:

根据权重随机选取指定条数记录的简单算法实现(C#)

//1.声明一个继承RandomObject的实体类,如:*
public class AdvertEntity : RandomObject
{
/// <summary>
/// 名称
/// </summary>
public string Name { set; get; }
/// <summary>
/// 描述
/// </summary>
public string Description { set; get; }
//...其它相关的字段/属性
}

//2.初始化调用数据,如:
//初始化模拟权重数据
List<Advert> list = new List<Advert>();
list.Add(new Advert { Name = "A", Weight = 1 });
list.Add(new Advert { Name = "B", Weight = 2 });
list.Add(new Advert { Name = "C", Weight = 2 });
list.Add(new Advert { Name = "D", Weight = 3 });
list.Add(new Advert { Name = "E", Weight = 4 });
list.Add(new Advert { Name = "F", Weight = 5 });
list.Add(new Advert { Name = "G", Weight = 60 });
//根据权重随机取指定记录条数
List<Advert> newList = RandomHelper.GetRandomList<Advert>(list, 2); //这个就是用法,newList就是随机取出的记录(第二个参数就是随机取多少条)

根据权重随机选取指定条数记录的简单算法实现(C#)

四.测试运行结果如下:

根据权重随机选取指定条数记录的简单算法实现(C#)

根据权重随机选取指定条数记录的简单算法实现(C#)

 
反对 0举报 0 评论 0
 

免责声明:本文仅代表作者个人观点,与乐学笔记(本网)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
    本网站有部分内容均转载自其它媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,若因作品内容、知识产权、版权和其他问题,请及时提供相关证明等材料并与我们留言联系,本网站将在规定时间内给予删除等相关处理.

  • 使用C#编写一个.NET分析器(一) 使用csv模块的什么方法可以一次性将一行数据写入文件
    使用C#编写一个.NET分析器(一) 使用csv模块的
    译者注这是在Datadog公司任职的Kevin Gosse大佬使用C#编写.NET分析器的系列文章之一,在国内只有很少很少的人了解和研究.NET分析器,它常被用于APM(应用性能诊断)、IDE、诊断工具中,比如Datadog的APM,Visual Studio的分析器以及Rider和Reshaper等等。之前
    03-08
  • 跨语言调用C#代码的新方式-DllExport 跨语言调用本质
    跨语言调用C#代码的新方式-DllExport 跨语言调
    简介上一篇文章使用C#编写一个.NET分析器文章发布以后,很多小伙伴都对最新的NativeAOT函数导出比较感兴趣,今天故写一篇短文来介绍一下如何使用它。在以前,如果有其他语言需要调用C#编写的库,那基本上只有通过各种RPC的方式(HTTP、GRPC)或者引入一层C++
    03-08
  • 我比较了 Go 和 C# 的速度
    我比较了 Go 和 C# 的速度
    我在 Go 和 C# 之间进行了速度比较。我通常使用 C#,但我有机会使用 Go,并且由于传闻 Go 速度很快,所以我实际测量了它。测量内容我在 Go 和 C# 中执行了一个简单的循环和判断过程,以查看整数 2 到 N 是否为质数。来源是Github参考。测量模式 逻辑内核 8 Wi
    03-08
  • [C#]使用 AltCover 获得代码覆盖率 - E2E Test 和 Unit Test
    [C#]使用 AltCover 获得代码覆盖率 - E2E Test
    背景在 CI/CD 流程当中,测试是 CI 中很重要的部分。跟开发人员关系最大的就是单元测试,单元测试编写完成之后,我们可以使用 IDE 或者 dot cover 等工具获得单元测试对于业务代码的覆盖率。不过我们需要一个独立的 CLI 工具,这样我们才能够在 Jenkins 的 CI
  • C#中LINQ的Select与SelectMany函数如何使用 c反应蛋白高说明什么
    C#中LINQ的Select与SelectMany函数如何使用 c反
    本篇内容主要讲解“C#中LINQ的Select与SelectMany函数如何使用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C#中LINQ的Select与SelectMany函数如何使用”吧!LINQ的Select与SelectMany函数使用Select扩展函
    02-09 linqselect
  • PerfView专题 (第三篇):如何寻找 C# 中的 VirtualAlloc 内存泄漏
    PerfView专题 (第三篇):如何寻找 C# 中的 Virt
    一:背景上一篇我们聊到了如何用 PerfView 去侦察 NTHeap 的内存泄漏,这种内存泄漏往往是用 C 的 malloc 或者 C++ 的 new 分配而不释放所造成的,这一篇我们来聊一下由 VirtualAlloc 方法造成的泄漏如何去甄别?了解 VirtualAlloc 的朋友肯定说, C# 这种高
    02-09
  • Blazor和Vue对比学习(知识点杂锦3.04):Blazor中C#和JS互操作(超长文)
    Blazor和Vue对比学习(知识点杂锦3.04):Blazo
    C#和JS互操作的基本语法是比较简单的,但小知识点特别多,同时,受应用加载顺序、组件生命周期以及参数类型的影响,会有比较多坑,需要耐心的学习。在C#中调用JS的场景会比较多,特别是在WASM模式下,由于WebAssembly的限制,很多时候,还是需要借助JS去控制D
    02-09
  • 的键">C#怎么使用struct类型作为泛型Dictionary
    本文小编为大家详细介绍“C#怎么使用struct类型作为泛型DictionaryTKey,TValue的键”,内容详细,步骤清晰,细节处理妥当,希望这篇“C#怎么使用struct类型作为泛型DictionaryTKey,TValue的键”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学
  • C#如何实现折半查找算法 彩票查询
    C#如何实现折半查找算法 彩票查询
    本篇内容主要讲解“C#如何实现折半查找算法”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C#如何实现折半查找算法”吧!折半查找,也叫二分查找,当在一个数组或集合中查找某个元素时,先定位出中间位置元素
    02-09
  • C#如何实现选择排序 c罗
    C#如何实现选择排序 c罗
    本篇内容主要讲解“C#如何实现选择排序”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C#如何实现选择排序”吧!选择排序是一种低效的排序算法,大致过程是:遍历数组的每一个元素,先假设0号位置上的元素是最
    02-09
点击排行