根據權重隨機選取指定條數記錄的簡單演算法實現(C#)【含原始碼】

來源:互聯網
上載者:User

一.應用情境:

    有時我們需要從一些列資料中根據權重隨機選取指定條數記錄出來,這裡需要權重、隨機,我們根據權重越大的,出現機率越大。例如廣告系統:可根據客戶支付金額大小來調控客戶們的廣告出現機率,客戶支付金額越大,其廣告出現頻率越頻繁,例如:加入有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,以後只要繼承該類即可。其代碼如下:

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

這個類我們只定義一個Weight屬性,其它屬性可由繼承它的類根據具體業務來實現具體屬性。

 

2.建立一個輔助類RandomHelper,新增一個實現根據權重隨機選取條數的的函數,其代碼如下:

 

    /// <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;
}


 

為了適合各個情境,我們定義T是一個泛型類,該類務必繼承RandomObject類,實現自己類資訊。該方法有相關的注釋,這裡就不再詳細重複描述。

 

特別注意一下GetRandomSeed()這個函數,這個是為了防止在短時間內頻繁建立和調用Random時候,會出現重複的隨機數(也就是隨機不在是隨機的問題),其函數代碼如下:

 

 

    /// <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);
}

 

 

3.調用方法:

調用方法很簡單,只需要聲明一個自己的實體,整合Object,然後根據實際情況直接調用RandomHelper.GetRandomList()方法即可。

如下:

 

//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就是隨機取出的記錄(第二個參數就是隨機取多少條)

 

 

 

 

 

四.測試回合結果如下:

 

 

 

五.附原始碼下載:

 點擊下載原始碼

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.