2009-09-11 36 views
1

我有對象列表的字典,如下所示:舍入值的陣列,以100%

IDictionary<string, IList> MyItemDictionary 

我通過用下面的代碼字典做一個對每個鍛鍊百分比:

IList<double> percentages = new List<double>();  

foreach(KeyValuePair<string, IList> pair in MyItemDictionary) 
{ 
    double percentage = (100d/totalItemsCount)*pair.Value.Count; 
    percentages.Add(percentage); 
} 

基本上我需要處理百分比列表並將每個百分比四捨五入到一個整數,但是將它們加起來爲100.精度不是最重要的,但是小於1的百分比,即0.45需要四捨五入到1。

有誰知道如何做到這一點?

+3

如果您的列表包含1,1和1,您希望發生什麼? – Ruffles 2009-09-11 13:02:19

+0

我上面第二條評論:請提供數字示例;您的目標不明確如問題 – mjv 2009-09-11 13:16:31

+0

中所述嗨,感謝您的回覆。 如果我有3套1我會把它們擴大到33,33和34。基本上我用這個結果填充10 x 10格。 – Adam 2009-09-11 15:17:44

回答

3

如果您的百分比列表中包含1.5 + 1.5 + .. + 1.5 = 100.0,並且您將它們舍入爲2 + 2 + .. + 2,那麼最終的總數將爲134條目),而不是100.解決這個問題的方法是在現有百分比中分配錯誤(134-100 = 34)。在這種情況下,您會從34個百分比中減去1,因此您最終得到一系列1 + 2 + 1 + 2 + .. + 2 = 100.0。

要找到「其他」意味着你只需要int(numberOfPercentages/theError),那應該給你間隔。

此外,您必須注意不要從您的1分以下的百分比中減去任何東西。

哦,如果你所有的百分比是子1,這個問題不能得到解決:-(

1

你可以有一個「其他」或「其它」類別嗎?如果你有很多很小的比例,而你你可能需要一個最小的閾值,超過這個閾值你會把所有的東西都混雜在一起作爲其他的東西。

否則,我第二個wic關於總結百分比找到錯誤,然後將錯誤分佈在最大百分比上。

+0

這也將整齊地解決什麼時候有101個項目在列表中的問題 – Ruffles 2009-09-11 13:40:54

+0

這是一個有趣的建議......我可能會使用它。 謝謝! – Adam 2009-09-11 15:19:05

1

這是我的C#實現Largest Remainder Method。我還沒有廣泛測試,但迄今爲止非常好。可能有一些邊緣情況不起作用。

下面是一個示例呼叫:

變種未四捨五入=新列表{1.0M,1.5M,1.5M,1.5M,1.5M,1.5M,1.5M,1.5M,1.5M,1.5M, 1.5M,1.5M,1.5M,1.5M,1.5M,1.5M,1.5M,1.5M,1.5M,1.5M,1.5M,1.5M,1.5M,1.5M,1.5M, ,1.5M,1.5M,1.5M,1.5M,1.5M,1.5M,1.5M,1.5M,1.5M,1.5M,1.5M,1.5M,1.5M,1.5M,1.5M,1.5 M,1.5M,1.5M,1.5M,1.5M,1.5M,1.5M,1.5M,1.5M,1.5M,1.5M,1.5M,1.5M,1.5M,1.5M,1.5M, 1.5M,1.5M,1.5M,1.5M,1.5M,1.5M,1.5M};

var rounded = RoundNumberList(unrounded);

/// <summary> 
    /// Round list of numbers using the Largest Remainder Method. Sum of Numbers should equal 100. 
    /// </summary> 
    /// <param name="Numbers">List of decimals numbers to round</param> 
    /// <returns>Rounded list of integers</returns> 
    public static List<int> RoundNumberList(List<decimal> Numbers) 
    { 
     int sum = 0; 
     var rounded = new Dictionary<int, decimal>(); 

     for (int i = 0; i < Numbers.Count; i++) 
     { 
      rounded.Add(i, Numbers[i]); 
      sum += (int)Numbers[i]; 
     } 

     if (sum > 100) 
      throw new Exception("The sum of all numbers is > 100."); 

     if (100 - sum > Numbers.Count) 
      throw new Exception("The sum of all numbers is too low for rounding: " + sum.ToString()); 

     if (sum < 100) 
     { 
      // Sort descending by the decimal portion of the number 
      rounded = rounded.OrderByDescending(n => n.Value-(int)n.Value).ToDictionary(x => x.Key, x => x.Value); 

      int i = 0; 
      int diff = 100 - sum; 

      foreach (var key in rounded.Keys.ToList()) 
      { 
       rounded[key]++; 
       i++; 
       if (i >= diff) break; 
      } 

      // Put back in original order and return just integer portion 
      return rounded.OrderBy(n => n.Key).Select(n => (int)n.Value).ToList(); 
     } 
     else 
     { 
      // Return just integer portion 
      return rounded.Select(n => (int)n.Value).ToList(); 
     } 
    }