2009-09-11 3 views
1

У меня есть словарь списков объектов, как показано ниже:Завершают массивы значений до 100%

IDictionary<string, IList> MyItemDictionary 

Я работаю проценты по делать для каждого по словарю следующего кода:

В основном мне нужно обработать список процентов и округлить каждый процент до целого числа, НО их добавить до 100. Точность не имеет наивысшего значения, а под 1 процент, то есть 0,45 необходимо округлить до 1.

Кто-нибудь знает, как это сделать?

+3

Если ваш список содержит 1, 1 и 1, что бы вы хотели сделать? – Ruffles

+0

Второй комментарий выше: укажите числовые примеры; ваша цель неясна, как указано в вопросе – mjv

+0

Привет, спасибо за ваши ответы. Если бы у меня было 3 набора из 1, я бы расширил их до 33, 33 и 34.В основном я заполняю сетку размером 10 х 10 с результатами этого. – Adam

ответ

3

Если ваш процентный список заканчивается с 1,5 + 1,5 + .. + 1,5 = 100,0, и вы должны были округлить их до 2 + 2 + .. + 2, вы в итоге получили бы 134 как общую сумму (~ 67 записи), а не 100. Способ исправить это состоит в распространении ошибки (134-100 = 34) среди существующих процентов. В этом случае вы вычтите 1 из 34 процентов, так что вы получите серию из 1 + 2 + 1 + 2 + .. + 2 = 100.0.

Чтобы узнать, что означает «каждый другой» означает, что вы просто выполняете int (numberOfPercentages/theError), и это должно дать вам интервал.

Кроме того, вы должны позаботиться о том, чтобы не вычитать что-либо из вашего 1-го процента.

О, и в случае, если все ваши проценты к югу 1, эта проблема не может быть решена :-(

1

Вы можете иметь «Other» или категории «Разные»? Если у вас есть много небольшого процента, и вы вокруг вас все вверх или вниз, вы будете накапливать огромную ошибку, как указывал Вик. Возможно, вам понадобится минимальный порог, за которым вы будете объединять все вместе как разные вещи.

В противном случае, вторая идея wic о суммировании процентов к найти ошибку, а затем распределить ошибку по наибольшему проценту.

+0

Это также решило бы проблему, когда в списке есть 101 элемент – Ruffles

+0

Это интересное предложение ... Я могу использовать его. Спасибо! – Adam

1

Посмотрите на how seats in a parliament are assigned на основе голосов за пропорциональное представительство. Я бы предложил largest remainder method, потому что он использует время, пропорциональное количеству элементов в вашем списке.

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.5M, 1.5M, 1.5M, 1.5 М, 1,5М, 1,5М, 1,5М, 1,5М, 1,5М, 1,5М, 1,5М, 1,5М, 1,5М, 1,5М, 1,5М, 1,5М, 1,5М, 1,5М, 1,5М, 1,5М, 1.5M, 1.5M, 1.5M, 1.5M, 1.5M, 1.5M, 1.5M};

var rounded = RoundNumberList (не указано);

/// <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(); 
     } 
    } 
Смежные вопросы