Округление массивов значений до 100% - PullRequest
1 голос
/ 11 сентября 2009

У меня есть словарь списков объектов, как показано ниже:

IDictionary<string, IList> MyItemDictionary

Я вычисляю проценты, выполняя a для каждого словаря с кодом ниже:

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.

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

Ответы [ 4 ]

3 голосов
/ 11 сентября 2009

Если ваш процентный список в конечном итоге содержит 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 голос
/ 04 ноября 2016

Это моя реализация C # метода наибольшего остатка . Я не проверял это всесторонне, но пока все хорошо. Могут быть некоторые крайние случаи, когда это не работает.

Вот пример звонка:

переменная без заземления = новый список {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,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,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,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,5М, 1,5М 1,5М, 1,5М, 1,5М};

var округлено = 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();
        }
    }
1 голос
/ 12 сентября 2009

Посмотрите на , как распределяются места в парламенте на основе голосов за пропорциональное представительство. Я бы предложил метод наибольшего остатка , потому что он использует время, пропорциональное количеству элементов в вашем списке.

1 голос
/ 11 сентября 2009

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...