mirror of
https://github.com/nsnail/spectre.console.git
synced 2025-04-24 20:22:51 +08:00

This also cleans up the bar chart code slightly and fixes some minor bugs that were detected in related code. Closes #244
73 lines
2.4 KiB
C#
73 lines
2.4 KiB
C#
// Ported from Rich by Will McGugan, licensed under MIT.
|
|
// https://github.com/willmcgugan/rich/blob/527475837ebbfc427530b3ee0d4d0741d2d0fc6d/rich/_ratio.py
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Linq;
|
|
|
|
namespace Spectre.Console
|
|
{
|
|
internal static class Ratio
|
|
{
|
|
public static List<int> Reduce(int total, List<int> ratios, List<int> maximums, List<int> values)
|
|
{
|
|
ratios = ratios.Zip(maximums, (a, b) => (ratio: a, max: b)).Select(a => a.max > 0 ? a.ratio : 0).ToList();
|
|
var totalRatio = ratios.Sum();
|
|
if (totalRatio <= 0)
|
|
{
|
|
return values;
|
|
}
|
|
|
|
var totalRemaining = total;
|
|
var result = new List<int>();
|
|
|
|
foreach (var (ratio, maximum, value) in ratios.Zip(maximums, values))
|
|
{
|
|
if (ratio != 0 && totalRatio > 0)
|
|
{
|
|
var distributed = (int)Math.Min(maximum, Math.Round((double)(ratio * totalRemaining / totalRatio)));
|
|
result.Add(value - distributed);
|
|
totalRemaining -= distributed;
|
|
totalRatio -= ratio;
|
|
}
|
|
else
|
|
{
|
|
result.Add(value);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public static List<int> Distribute(int total, IList<int> ratios, IList<int>? minimums = null)
|
|
{
|
|
if (minimums != null)
|
|
{
|
|
ratios = ratios.Zip(minimums, (a, b) => (ratio: a, min: b)).Select(a => a.min > 0 ? a.ratio : 0).ToList();
|
|
}
|
|
|
|
var totalRatio = ratios.Sum();
|
|
Debug.Assert(totalRatio > 0, "Sum or ratios must be > 0");
|
|
|
|
var totalRemaining = total;
|
|
var distributedTotal = new List<int>();
|
|
|
|
minimums ??= ratios.Select(_ => 0).ToList();
|
|
|
|
foreach (var (ratio, minimum) in ratios.Zip(minimums, (a, b) => (a, b)))
|
|
{
|
|
var distributed = (totalRatio > 0)
|
|
? Math.Max(minimum, (int)Math.Ceiling(ratio * totalRemaining / (double)totalRatio))
|
|
: totalRemaining;
|
|
|
|
distributedTotal.Add(distributed);
|
|
totalRatio -= ratio;
|
|
totalRemaining -= distributed;
|
|
}
|
|
|
|
return distributedTotal;
|
|
}
|
|
}
|
|
}
|