mirror of
https://github.com/nsnail/spectre.console.git
synced 2025-08-04 04:47:59 +08:00

committed by
Patrik Svensson

parent
0b4321115a
commit
9637066927
@ -6,6 +6,19 @@ namespace Spectre.Console.Internal
|
||||
{
|
||||
internal static class EnumerableExtensions
|
||||
{
|
||||
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
|
||||
{
|
||||
foreach (var item in source)
|
||||
{
|
||||
action(item);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool AnyTrue(this IEnumerable<bool> source)
|
||||
{
|
||||
return source.Any(b => b);
|
||||
}
|
||||
|
||||
public static IEnumerable<(int Index, bool First, bool Last, T Item)> Enumerate<T>(this IEnumerable<T> source)
|
||||
{
|
||||
if (source is null)
|
||||
@ -40,5 +53,18 @@ namespace Spectre.Console.Internal
|
||||
{
|
||||
return source.Select((value, index) => func(value, index));
|
||||
}
|
||||
|
||||
public static IEnumerable<(TFirst First, TSecond Second)> Zip<TFirst, TSecond>(
|
||||
this IEnumerable<TFirst> source, IEnumerable<TSecond> first)
|
||||
{
|
||||
return source.Zip(first, (first, second) => (first, second));
|
||||
}
|
||||
|
||||
public static IEnumerable<(TFirst First, TSecond Second, TThird Third)> Zip<TFirst, TSecond, TThird>(
|
||||
this IEnumerable<TFirst> first, IEnumerable<TSecond> second, IEnumerable<TThird> third)
|
||||
{
|
||||
return first.Zip(second, (a, b) => (a, b))
|
||||
.Zip(third, (a, b) => (a.a, a.b, b));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
75
src/Spectre.Console/Internal/Utilities/Ratio.cs
Normal file
75
src/Spectre.Console/Internal/Utilities/Ratio.cs
Normal file
@ -0,0 +1,75 @@
|
||||
// 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
|
||||
{
|
||||
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(ratio * totalRemaining / (double)totalRatio));
|
||||
result.Add(value - distributed);
|
||||
totalRemaining -= distributed;
|
||||
totalRatio -= ratio;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Add(value);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static List<int> Distribute(int total, List<int> ratios, List<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>();
|
||||
|
||||
if (minimums == null)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user