2010-09-03 97 views
3

我正在研究一個涉及將電話轉接到多個目的地的項目。計算百分比分配中的下一個項目

例如,我想:呼叫

  • 10%去目的地的呼叫的
  • 20%去目的地乙呼叫
  • 30%去目的地Ç
  • 電話
  • 40%去到目的地d

目的地的數量及比例必須是可配置的。


我一直在思考如何做到這一點,電子表格和一些代碼打過來,我想出了這個:

對於每個目標,採取隨機數,由乘以百分比,然後選擇號碼最高的目的地。就像這樣:

Item: RANDOM * PERCENTAGE = RESULT 
    A: 48 *  10  = 480 
    B: 33 *  20  = 660 
    C: 81 *  30  = 2430 <--- Highest number, select C 
    D: 5 *  40  = 200 

我想我的工作了作爲d顯然是選擇最多,其次是C,那麼B,和最全A的

但它不工作。如果我這樣做5000次,並計算時代的實際百分比選擇的每個目的地時,我得到這個:電話

  • 1%去目的地的呼叫的
  • 12%去目的地B.呼叫
  • 31%去目的地的C調用的
  • 56%去目的地d

這裏是我用來測試本的代碼:

// Initialise item weighting percentages 
Dictionary<string, int> weighting = new Dictionary<string, int>(); 
weighting["A"] = 10; //10% 
weighting["B"] = 20; //20% 
weighting["C"] = 30; //30% 
weighting["D"] = 40; //40% (total = 100%) 

// Initialise data set used for each iteration 
Dictionary<string, int> data = new Dictionary<string, int>(); 

// Initialise counts of the selected items 
Dictionary<string, int> count = new Dictionary<string, int>(); 
count["A"] = 0; 
count["B"] = 0; 
count["C"] = 0; 
count["D"] = 0; 

Random rand = new Random(); 

// Loop 5000 times 
for (int i = 0; i < 5000; i++) { 

    // For each item, get a random number between 0 and 99 
    // and multiply it by the percentage to get a 
    // weighted random number. 
    data["A"] = rand.Next(100) * weighting["A"]; 
    data["B"] = rand.Next(100) * weighting["B"]; 
    data["C"] = rand.Next(100) * weighting["C"]; 
    data["D"] = rand.Next(100) * weighting["D"]; 

    // Find which item came out on top and increment the count 
    string sel = data.First(x => x.Value == data.Max(y => y.Value)).Key; 
    count[sel]++; 

    // Log, so you can see whats going on... 
    if (i < 15) 
     Console.WriteLine("A:{0:00000} B:{1:00000} C:{2:00000} D:{3:00000} SELECTED:{4}", 
      data["A"], data["B"], data["C"], data["D"], sel); 
    else if (i == 15) Console.WriteLine("..."); 

} 

// Output the results, showing the percentage of the number 
// occurrances of each item. 
Console.WriteLine(); 
Console.WriteLine("Results: "); 
Console.WriteLine(" A = {0}%", 100 * ((double)count["A"]/(double)count.Sum(z => z.Value))); 
Console.WriteLine(" B = {0}%", 100 * ((double)count["B"]/(double)count.Sum(z => z.Value))); 
Console.WriteLine(" C = {0}%", 100 * ((double)count["C"]/(double)count.Sum(z => z.Value))); 
Console.WriteLine(" D = {0}%", 100 * ((double)count["D"]/(double)count.Sum(z => z.Value))); 

results是:

A:00780 B:00300 C:01740 D:03680 SELECTED:D 
A:00600 B:00660 C:00060 D:03400 SELECTED:D 
A:00900 B:01880 C:00510 D:00720 SELECTED:B 
A:00260 B:01380 C:00540 D:01520 SELECTED:D 
A:00220 B:01960 C:00210 D:02080 SELECTED:D 
A:00020 B:01400 C:01530 D:00120 SELECTED:C 
A:00980 B:00400 C:01560 D:03280 SELECTED:D 
A:00330 B:00300 C:01500 D:03680 SELECTED:D 
A:00590 B:00460 C:02730 D:02400 SELECTED:C 
A:00580 B:01900 C:02040 D:01320 SELECTED:C 
A:00620 B:01320 C:00750 D:01760 SELECTED:D 
A:00320 B:01040 C:01350 D:03640 SELECTED:D 
A:00340 B:01520 C:02010 D:03880 SELECTED:D 
A:00850 B:01420 C:00480 D:03400 SELECTED:D 
A:00560 B:00680 C:00030 D:00000 SELECTED:B 
... 

Results: 
    A = 1.44% 
    B = 11.54% 
    C = 30.6% 
    D = 56.42% 

任何人都可以提出一個方法來解決這個問題,做到真正的百分比出來的配置?


而對於加分,任何人都可以提出一個方法做類似的但不使用隨機數的東西,所以選擇目的地的順序明確的規定。用上面的例子會輸出這個序列每次:

ABCDBCDCDD ABCDBCDCDD ABCDBCDCDD ABCDBCDCDD ... 

(注意順序均勻分佈)

感謝。 Ben

+0

任何人都可以用編輯權限解決這個代碼格式化我嗎?我無法弄清楚什麼是錯的!它全部縮進4個空格... – BG100 2010-09-03 08:33:59

+1

@BG:請在自己的段落中使用'----',而不是'


'來插入水平線。 – kennytm 2010-09-03 08:35:42

+0

完美...謝謝。 – BG100 2010-09-03 08:38:54

回答

5

好吧,我已經在模擬做過無數次,這裏的基本方法是我使用(不正確的錯誤檢查):

您需要想象橫跨從0頁面中的畫線現在我們正在做的是將這一線按比例分配到您的目的地。然後我們使用隨機數字來選擇這一行上的一個點。具有該區域的目的地是所選的那個區域。

編輯:嘗試在線圖

|-----------------------------------------------------| Line 1 to 100 
|-----|----------|---------------|--------------------| Line split proportionally 
0 A 10 B 30  C  60  D   100 

我們可以做到這一點,如下所示。

假設您的目標百分比位於數組中,而不是單獨的變量中。

int totalPercentages = 0; 
int destinationsIndex = -1; 
int randomNumberBetween0and100 = GetRandomNumber(); 
for(int i = 0; i < destinationPercentageArrays.Length; i++) 
{ 
    totalPercentages += destinationPercentageArrays[i]; 
    if (totalPercentages > randomNumberBetween0and100) 
    { 
     destinationIndex = i; 
     break; 
    } 
} 

if (destinationIndex == -1) 
{ 
    throw new Exception("Something went badly wrong."); 
} 

現在變量destinationIndex指向選定的目的地。

+0

啊,是的...這看起來像我需要的解決方案,謝謝。 – BG100 2010-09-03 09:11:20

+0

剛剛發現了額外的一點...想着它... – 2010-09-03 09:20:28

+0

我會......不用擔心!只要給其他人一個機會來提供他們的意見。你對最後一點有什麼想法嗎? – BG100 2010-09-03 09:24:18

1

另一種可能性是用for循環填充一個大小爲100的列表並插入每個值乘以其權重。然後隨機選擇一個列表項。

實施例,短列表(10項)

  • 5X甲
  • 4倍乙
  • 1XÇ

列表= {A,A,A,A,A,B ,B,B,B,C}

0和9之間的隨機數。

+0

+1這是一個非常簡單的方法來做到這一點,謝謝!但我想我會和Herbie博士的回答一起去。 – BG100 2010-09-03 09:14:35

2

對於通過百分比分配你給做:

創建隨機數介於1和100(含)

If < 10 A 
If > 10 < 30 B 
If > 30 < 60 C 
If > 60 D 

至於如何有一個定義的列表的問題,只是把目的地按順序排列成一個數組,並逐一枚舉它們。當你用完時,從頭開始重新開始。

string[] destinations = new string[] { "A", "B", "C", "D", ... } 

int counter = 0; 

//when need routing 
RouteTo(destinations[counter]); 
counter++; 
if (counter == destinations.Length) 
{ 
    counter = 0; 
} 
+0

那麼這就是我想要發生的事情,那麼爲什麼我的結果會出現1%,12%,31%,56%? – BG100 2010-09-03 08:42:24

+0

那麼我該如何提出清單呢?項目的數量及其百分比在設計時是未知的,並且順序需要均勻分配,即這個:ABCDBCDCDD,不是這樣的:ABBCCCDDDD – BG100 2010-09-03 08:49:12

+0

您可以在運行時使用第一種生成具有定義百分比的隨機列表的方法創建列表。 – 2010-09-03 08:52:28

0

這將長100個字符創建一個隨機列表,即ABCDBCDCDD ...

static void Main() 
    { 
     var weighting = new Dictionary<char, int>(); 
     weighting['A'] = 10; //10% 
     weighting['B'] = 20; //20% 
     weighting['C'] = 30; //30% 
     weighting['D'] = 40; //40% (total = 100%) 

     var test = CreateOrder(weighting); 
    } 

    static IEnumerable<char> CreateOrder(Dictionary<char, int> weighting) 
    { 
     var list = new List<KeyValuePair<int, char>>(); 
     var random = new Random(); 
     foreach (var i in weighting) 
     { 
      for (int j = 0; j < i.Value; j++) 
      { 
       list.Add(new KeyValuePair<int, char>(random.Next(), i.Key)); 
      } 
     } 
     return list.OrderBy(u=>u.Key).Select(u => u.Value); 
    }