为列表中的每个项目设置权重

时间:2019-04-19 02:09:54

标签: c# algorithm list recursion functional-programming

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

例如:

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

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

重量总和必须等于100(%)

但是我不能设想一个数学函数来实现一个解决方案:

什么是实现此行为的良好通用算法?

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

1 个答案:

答案 0 :(得分:2)

这有助于分步思考。

让我们将其拆分为可行的列表...

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));

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