calcPercents function

List<double> calcPercents(
  1. List<double> values
)

Calculates percentage of values so the summ of the result values is always exactly equal to 100.

If values is empty, it returns the empty list.

If some of values are negative, they are trated as positive values in the calculation process. It means that negative values make a positive contribution in the total summ of values, but the resulting percents for them will be negative. E.g. the values of [10, 0, -10] will be converted into the [50.0%, 0.0%, -50.0%].

If the total summ of values is zero, it returns list of zeroes.

The accuracy of the result values is up to a tenth.

Implementation

List<double> calcPercents(final List<double> values)
{
  if (values.isEmpty) return const [];
  final total = values.fold(0.0, (sum, val) => sum + val.abs());
  if (total == 0.0) return List.filled(values.length, 0.0);
  final per = values.map((e) => (e * 1000 / total).floor());
  final sum = per.fold(0, (sum, val) => sum + val.abs());
  var remaind = 1000 - sum;
  if (remaind != 0) {
    final nonZero = values.where((e) => e != 0.0).length;
    final piece = max(remaind.abs() ~/ nonZero, 1) * remaind.sign;
    final res = List<double>.filled(values.length, 0.0);
    var i = 0;
    for (var p in per) {
      if (values[i] != 0.0) {
        if (remaind != 0) {
          res[i] = (p + piece * p.sign) / 10;
          remaind -= piece;
        } else {
          res[i] = p / 10;
        }
      }
      ++i;
    }
    return res;
  }
  return per.map((e) => e / 10).toList(growable: false);
}