复合类的可重用匿名排名函数

本文关键字:函数 复合 | 更新日期: 2023-09-27 17:57:11

我有一个复合类,由来自不同来源的统计信息类组成。 复合类根据统计信息类中的排序和排名属性获得"总分"。

例如,统计信息类可能如下所示:

public class StatsTypeA
{
    public int PropAX { get; set; }
    public int PropAXPoints { get; set; }
    public int PropAY { get; set; }
    public int PropAYPoints { get; set; }
}

复合类就像这个例子:

class CompositeType
{
    public StatsTypeA StatsA { get; set; }
    public StatsTypeB StatsB { get; set; }
    public int Id { get; set; }
    public int TotalPoints
    {
        get
        {
            return StatsA.PropAXPoints + StatsA.PropAYPoints +                 StatsB.PropBXPoints + StatsB.PropBYPoints;
        }
    }
}

在主类中,将有一个复合类列表,这些复合类具有类中每个属性的值:

List<CompositeType> participants = new List<CompositeType>();

我想对它们进行排序和排名,并且可以通过蛮力做到这一点,但找不到一种不重复一堆代码的方法。 例如,单个属性的排名和评分可能为:

var statsX = composites.GroupBy(s => s.StatsA.PropAX,
                            s => s.Id,
                            (key, group) => (new
                            {
                              Stats = key,
                              Participants = group.ToList()
                            }))
                   .OrderBy(s => s.Stats);
int points = 0;
foreach (var statGroup in statsX)
{
    var maxPoints = points + statGroup.Participants.Count * 2 - 2;
    var thisPoints = (points + maxPoints) / 2;
    foreach (var id in statGroup.Participants)
    {
        composites.Single(data => data.Id == id).StatsA.PropAXPoints = points;
    }
    points = maxPoints + 2;
}

有没有办法使用上面 LINQ 语句中的匿名类型创建可重用的匿名函数? 换句话说,我怎样才能有一个单一的函数/扩展方法来对每个单独的统计属性进行排名?

复合类的可重用匿名排名函数

这是我想出的通用方法:

Action<IEnumerable<CompositeType>, Func<CompositeType, int>, Action<CompositeType, int>> compute =
    (cs, f, a) =>
    {
        var stats =
            from c in cs
            group c by f(c) into gs
            orderby gs.Key
            select new
            {
                Stats = gs.Key,
                Participants = gs.ToList()
            };
        stats.Aggregate(0, (points, statGroup) =>
        {
            var maxPoints = points + statGroup.Participants.Count * 2 - 2;
            var avgPoints = (points + maxPoints)/2;
            statGroup.Participants.ForEach(c => a(c, avgPoints));
            return maxPoints + 2;
        });
    };

现在我可以这样称呼它:

compute(composites, c => c.StatsA.PropAX, (c, p) => c.StatsA.PropAXPoints = p);
compute(composites, c => c.StatsA.PropAY, (c, p) => c.StatsA.PropAYPoints = p);
compute(composites, c => c.StatsB.PropBX, (c, p) => c.StatsB.PropBXPoints = p);
compute(composites, c => c.StatsB.PropBY, (c, p) => c.StatsB.PropBYPoints = p);

这就是你所追求的吗?