首页 > 解决方案 > 为列表中的每个项目设置权重

问题描述

我有一个以逗号分隔的水果列表,它们按从最相关到​​最不相关的顺序列出。

例如:

"fruits":"apple, orange, lemon, apple, strawberry, pineapple, banana"

我需要根据列出的顺序和每个项目的重复次数为列表中的每个元素分配权重。

权重总和必须 = 100 (%)

但我无法想出一个数学函数来实现解决方案:

什么是实现这种行为的好通用算法?

也许 C# 中已经有一些选项可用?

标签: c#algorithmlistrecursionfunctional-programming

解决方案


它有助于逐步思考。

让我们把它分成一个可行的列表......

var fruitList = "apple, orange, lemon, apple, strawberry, pineapple, banana"
  .Split(", ".ToCharArray())

...它带有一个代表订单的索引,因为这很重要。

.Select((name, index) => {
  return new {name, index + 1};
})

我们必须停下来想想订单与次数的相关性。他们必须在彼此之间分享分配的 100,但如何?订单真的很重要,而次数不那么重要(99/1),反之亦然(1/99),还是50/50?

让我们假设他们将相关性分成 50/50。您可以降低此数字以提供与次数更多的相关性,或增加它以使订单更具相关性。

var orderRelevance = .5;
var timesRelevance = 1 - orderRelevance;

假设它们都是唯一的,则时间相关性将是为时间相关性分配的权重除以水果的总数。

var timesWeightForOne = 100 * timesRelevance / fruitList.Count;

然后我们将分配剩余的 50%。我们假设它应该是线性分布的。

var orderWeightForOne = 100 * orderRelevance / fruitList.Sum(fruit => fruit.Index);

现在在计算权重时对它们进行分组。

var weighted = fruitList
  .GroupBy(
    fruit => fruit.name,
    (name, fruits) => new {
      name,
      weight = fruits.Count() * timesWeightForOne + 
               fruits.Sum(fruit => fruit.index) * orderWeightForOne;
    }
 )

让我们按重量降序排列它们。

 .OrderByDescending(fruit => fruit.weight)

并使它们可读。

 .Select(fruit => {
   var percent = Math.Round(fruit.weight, 2);
   return $"{fruit.name}: {percent}%";
 })

 Console.WriteLine(string.Join("\r\n", weighted));

我不在编译器附近,所以可能会有错误,但这应该是要点。


推荐阅读