将列表中小于 1% 的数字设置为 1%,同时保持总数为 100%
Setting number in list that's less than 1% to 1% while keeping total 100%
我 运行 我的 Web 应用程序存在逻辑问题。
背景:页面上会出现一排 div。他们的 CSS width:
百分比等于项目的 int
值 div 与列表的总 int
值的百分比。
问题:我不希望任何宽度小于 1%。这意味着我必须将低于 1% 的项目的宽度增加到 1%,并减少所有其他项目的宽度,以便总百分比加起来正好达到 100%。
这会产生一个问题,即本来正好是 1% 的项目会减少到不到 1%。
我已经尝试了很多方法来做到这一点,但这是我当前的迭代。通过将它放入控制台应用程序,我为自己和你们简化了它。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PercentageOfTotal
{
public class Item
{
public int Value { get; set; }
public double Percent { get; set; }
}
class Program
{
static void Main(string[] args)
{
var items = new List<Item>();
items.Add(new Item { Value = 26 });
items.Add(new Item { Value = 31 });
items.Add(new Item { Value = 47 });
items.Add(new Item { Value = 175 });
items.Add(new Item { Value = 50 });
items.Add(new Item { Value = 1 });
items.Add(new Item { Value = 74 });
items.Add(new Item { Value = 8 });
items.Add(new Item { Value = 219 });
items.Add(new Item { Value = 169 });
int sum = items.Sum(x => x.Value);
double minPercentage = 0.01;
System.Console.WriteLine("Value - Percent");
foreach (var item in items)
{
item.Percent = item.Value / (double)sum;
System.Console.WriteLine(item.Value + " - " + item.Percent);
}
System.Console.WriteLine("---------");
System.Console.WriteLine(items.Sum(x => x.Value) + " - " + items.Sum(x => x.Percent));
System.Console.WriteLine("\n");
var itemsLessThanOnePercent = items.Where(x => x.Percent < minPercentage).ToList();
var itemsGreaterThanOrEqualToOnePercent = items.Where(x => x.Percent >= minPercentage).ToList();
double totalPercentageLessThanOne = itemsLessThanOnePercent.Sum(x => x.Percent);
double reduceEachGreaterThanOneBy = ((itemsLessThanOnePercent.Count() * minPercentage) - totalPercentageLessThanOne) / itemsGreaterThanOrEqualToOnePercent.Count();
foreach (var item in itemsGreaterThanOrEqualToOnePercent)
{
item.Percent = item.Percent - reduceEachGreaterThanOneBy;
}
foreach (var item in itemsLessThanOnePercent)
{
item.Percent = minPercentage;
}
System.Console.WriteLine("Value - Percent");
foreach (var item in items)
{
System.Console.WriteLine(item.Value + " - " + item.Percent);
}
System.Console.WriteLine("---------");
System.Console.WriteLine(items.Sum(x => x.Value) + " - " + items.Sum(x => x.Percent));
System.Console.ReadLine();
}
}
}
如您所见,本例将 item
和 Value = 8
减少到小于 1% (0.009),因为 item.Value
一开始就已经是 1%。
基本上,我希望 item
的百分比相对于 item.Value
的总和,没有任何百分比小于 1%,并且百分比总和等于 100%。
如有任何帮助,我们将不胜感激。
您应该将项目计算为迭代,直到达到预期的百分比为止。你可以递归地做。我这样修改了你的代码;
static void Main()
{
var items = new List<Item>();
items.Add(new Item { Value = 26 });
items.Add(new Item { Value = 31 });
items.Add(new Item { Value = 47 });
items.Add(new Item { Value = 175 });
items.Add(new Item { Value = 50 });
items.Add(new Item { Value = 1 });
items.Add(new Item { Value = 74 });
items.Add(new Item { Value = 8 });
items.Add(new Item { Value = 219 });
items.Add(new Item { Value = 169 });
int sum = items.Sum(x => x.Value);
double minPercentage = 0.01;
System.Console.WriteLine("Value - Percent");
foreach (var item in items)
{
item.Percent = item.Value / (double)sum;
System.Console.WriteLine(item.Value + " - " + item.Percent);
}
System.Console.WriteLine("---------");
System.Console.WriteLine(items.Sum(x => x.Value) + " - " + items.Sum(x => x.Percent));
System.Console.WriteLine("\n");
CalculatePercents(items,minPercentage);
System.Console.WriteLine("Value - Percent");
foreach (var item in items)
{
System.Console.WriteLine(item.Value + " - " + item.Percent);
}
System.Console.WriteLine("---------");
System.Console.WriteLine(items.Sum(x => x.Value) + " - " + items.Sum(x => x.Percent));
System.Console.ReadLine();
Console.ReadLine();
}
private static void CalculatePercents(List<Item> items,double minPercentage)
{
var itemsLessThanOnePercent = items.Where(x => x.Percent < minPercentage).ToList();
var itemsGreaterThanOrEqualToOnePercent = items.Where(x => x.Percent >= minPercentage).ToList();
double totalPercentageLessThanOne = itemsLessThanOnePercent.Sum(x => x.Percent);
double reduceEachGreaterThanOneBy = ((itemsLessThanOnePercent.Count() * minPercentage) - totalPercentageLessThanOne) / itemsGreaterThanOrEqualToOnePercent.Count();
foreach (var item in itemsGreaterThanOrEqualToOnePercent)
{
item.Percent = item.Percent - reduceEachGreaterThanOneBy;
}
foreach (var item in itemsLessThanOnePercent)
{
item.Percent = minPercentage;
}
var minPercentagesItems = items.Where(x => x.Percent < minPercentage).ToList();
if (minPercentagesItems.Count == 0)
{
return;
}
CalculatePercents(minPercentagesItems,minPercentage);
}
您可以按 Value
递增的顺序枚举项目。对于每个项目,分配百分比,如果小于最小值 - 结转溢出以分配给其余项目。好吧,我承认这很难用语言来解释,所以这里是示例代码:
double overflow = 0;
int left = items.Count;
// loop in order of ascending value
foreach (var item in items.OrderBy(c => c.Value))
{
// calculate part of overflow to assign to this item, based on total and how much items still left
var overflowForItem = overflow / left;
// assign a bit less than expected if there is overflow
item.Percent = (item.Value - overflowForItem) / (double)sum;
// reduce overflow (we just assigned part of it above)
overflow -= overflowForItem;
if (item.Percent < minPercentage) {
overflow += (minPercentage - item.Percent) * sum;
item.Percent = minPercentage;
}
left--;
}
我 运行 我的 Web 应用程序存在逻辑问题。
背景:页面上会出现一排 div。他们的 CSS width:
百分比等于项目的 int
值 div 与列表的总 int
值的百分比。
问题:我不希望任何宽度小于 1%。这意味着我必须将低于 1% 的项目的宽度增加到 1%,并减少所有其他项目的宽度,以便总百分比加起来正好达到 100%。
这会产生一个问题,即本来正好是 1% 的项目会减少到不到 1%。
我已经尝试了很多方法来做到这一点,但这是我当前的迭代。通过将它放入控制台应用程序,我为自己和你们简化了它。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PercentageOfTotal
{
public class Item
{
public int Value { get; set; }
public double Percent { get; set; }
}
class Program
{
static void Main(string[] args)
{
var items = new List<Item>();
items.Add(new Item { Value = 26 });
items.Add(new Item { Value = 31 });
items.Add(new Item { Value = 47 });
items.Add(new Item { Value = 175 });
items.Add(new Item { Value = 50 });
items.Add(new Item { Value = 1 });
items.Add(new Item { Value = 74 });
items.Add(new Item { Value = 8 });
items.Add(new Item { Value = 219 });
items.Add(new Item { Value = 169 });
int sum = items.Sum(x => x.Value);
double minPercentage = 0.01;
System.Console.WriteLine("Value - Percent");
foreach (var item in items)
{
item.Percent = item.Value / (double)sum;
System.Console.WriteLine(item.Value + " - " + item.Percent);
}
System.Console.WriteLine("---------");
System.Console.WriteLine(items.Sum(x => x.Value) + " - " + items.Sum(x => x.Percent));
System.Console.WriteLine("\n");
var itemsLessThanOnePercent = items.Where(x => x.Percent < minPercentage).ToList();
var itemsGreaterThanOrEqualToOnePercent = items.Where(x => x.Percent >= minPercentage).ToList();
double totalPercentageLessThanOne = itemsLessThanOnePercent.Sum(x => x.Percent);
double reduceEachGreaterThanOneBy = ((itemsLessThanOnePercent.Count() * minPercentage) - totalPercentageLessThanOne) / itemsGreaterThanOrEqualToOnePercent.Count();
foreach (var item in itemsGreaterThanOrEqualToOnePercent)
{
item.Percent = item.Percent - reduceEachGreaterThanOneBy;
}
foreach (var item in itemsLessThanOnePercent)
{
item.Percent = minPercentage;
}
System.Console.WriteLine("Value - Percent");
foreach (var item in items)
{
System.Console.WriteLine(item.Value + " - " + item.Percent);
}
System.Console.WriteLine("---------");
System.Console.WriteLine(items.Sum(x => x.Value) + " - " + items.Sum(x => x.Percent));
System.Console.ReadLine();
}
}
}
如您所见,本例将 item
和 Value = 8
减少到小于 1% (0.009),因为 item.Value
一开始就已经是 1%。
基本上,我希望 item
的百分比相对于 item.Value
的总和,没有任何百分比小于 1%,并且百分比总和等于 100%。
如有任何帮助,我们将不胜感激。
您应该将项目计算为迭代,直到达到预期的百分比为止。你可以递归地做。我这样修改了你的代码;
static void Main()
{
var items = new List<Item>();
items.Add(new Item { Value = 26 });
items.Add(new Item { Value = 31 });
items.Add(new Item { Value = 47 });
items.Add(new Item { Value = 175 });
items.Add(new Item { Value = 50 });
items.Add(new Item { Value = 1 });
items.Add(new Item { Value = 74 });
items.Add(new Item { Value = 8 });
items.Add(new Item { Value = 219 });
items.Add(new Item { Value = 169 });
int sum = items.Sum(x => x.Value);
double minPercentage = 0.01;
System.Console.WriteLine("Value - Percent");
foreach (var item in items)
{
item.Percent = item.Value / (double)sum;
System.Console.WriteLine(item.Value + " - " + item.Percent);
}
System.Console.WriteLine("---------");
System.Console.WriteLine(items.Sum(x => x.Value) + " - " + items.Sum(x => x.Percent));
System.Console.WriteLine("\n");
CalculatePercents(items,minPercentage);
System.Console.WriteLine("Value - Percent");
foreach (var item in items)
{
System.Console.WriteLine(item.Value + " - " + item.Percent);
}
System.Console.WriteLine("---------");
System.Console.WriteLine(items.Sum(x => x.Value) + " - " + items.Sum(x => x.Percent));
System.Console.ReadLine();
Console.ReadLine();
}
private static void CalculatePercents(List<Item> items,double minPercentage)
{
var itemsLessThanOnePercent = items.Where(x => x.Percent < minPercentage).ToList();
var itemsGreaterThanOrEqualToOnePercent = items.Where(x => x.Percent >= minPercentage).ToList();
double totalPercentageLessThanOne = itemsLessThanOnePercent.Sum(x => x.Percent);
double reduceEachGreaterThanOneBy = ((itemsLessThanOnePercent.Count() * minPercentage) - totalPercentageLessThanOne) / itemsGreaterThanOrEqualToOnePercent.Count();
foreach (var item in itemsGreaterThanOrEqualToOnePercent)
{
item.Percent = item.Percent - reduceEachGreaterThanOneBy;
}
foreach (var item in itemsLessThanOnePercent)
{
item.Percent = minPercentage;
}
var minPercentagesItems = items.Where(x => x.Percent < minPercentage).ToList();
if (minPercentagesItems.Count == 0)
{
return;
}
CalculatePercents(minPercentagesItems,minPercentage);
}
您可以按 Value
递增的顺序枚举项目。对于每个项目,分配百分比,如果小于最小值 - 结转溢出以分配给其余项目。好吧,我承认这很难用语言来解释,所以这里是示例代码:
double overflow = 0;
int left = items.Count;
// loop in order of ascending value
foreach (var item in items.OrderBy(c => c.Value))
{
// calculate part of overflow to assign to this item, based on total and how much items still left
var overflowForItem = overflow / left;
// assign a bit less than expected if there is overflow
item.Percent = (item.Value - overflowForItem) / (double)sum;
// reduce overflow (we just assigned part of it above)
overflow -= overflowForItem;
if (item.Percent < minPercentage) {
overflow += (minPercentage - item.Percent) * sum;
item.Percent = minPercentage;
}
left--;
}