程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 根據權重隨機選取指定條數記錄的簡單算法實現(C#)[含源代碼]

根據權重隨機選取指定條數記錄的簡單算法實現(C#)[含源代碼]

編輯:C#入門知識

一.應用場景:

    有時我們需要從一些列數據中根據權重隨機選取指定條數記錄出來,這裡需要權重、隨機,我們根據權重越大的,出現概率越大。例如廣告系統:可根據客戶支付金額大小來調控客戶們的廣告出現概率,客戶支付金額越大,其廣告出現頻率越頻繁,例如:加入有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就是隨機取出的記錄(第二個參數就是隨機取多少條)

 
 
 
 
 
四.測試運行結果如下:

  \


 \


 

五.附源代碼下載:http://www.BkJia.com/uploadfile/2012/0323/20120323085926146.zip
 


 摘自 零星碎事
 

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved