2009-09-11 69 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(); 
     } 
    }