我在列表中有一个对象,需要对几种不同的方式进行排名。当前的代码相当笨拙,因为它要求我分别处理每一列。例:

public class Data
{
    public int AValue { get; set; }
    public int ARanking { get; set; }
    public int BValue { get; set; }
    public int BRanking { get; set; }
    public int CValue { get; set; }
    public int CRanking { get; set; }
}

public class Container
{
    public List<Data> RankingData { get; set; }

    public void RankData()
    {
        int count = 1;

        foreach (Data item in RankingData.OrderBy(d => d.AValue))
        {
            item.ARanking = count;
            count++;
        }

        count = 1;

        foreach (Data item in RankingData.OrderBy(d => d.BValue))
        {
            item.BRanking = count;
            count++;
        }

        count = 1;

        foreach (Data item in RankingData.OrderBy(d => d.CValue))
        {
            item.CRanking = count;
            count++;
        }
    }
}


我要解决的问题是我想写大概这样的东西:

public void RankData<V, R>()
{
    int count = 1;

    foreach(Data item in RankingData.OrderBy(V))
    {
        item.R = count;
        count++;
    }
}


因此,由于需要更改排名逻辑(例如,处理平局决胜规则),因此我只编写一次代码,而不是复制代码20次以使规则匹配。我想念什么?

更新

以Tanzelax的解决方案为基础,这是我想出的扩展类:

public static class RankingExtension
{
    public static void SetRanking<TKey>(this List<Data> dataSet, bool Ascending, Func<Data, TKey> getOrderBy, Action<Data, int> setRank)
        where TKey : IComparable
    {
        var ordered = (Ascending) ? dataSet.OrderBy(getOrderBy) : dataSet.OrderByDescending(getOrderBy);

        int i = 1;
        foreach (Data item in ordered)
        {
            setRank(item, i);
            i++;
        }
    }
}


我必须添加一个开关,以便可以控制该字段是否按升序排序。在我的测试场景中,它会产生适当的输出:

    List<Data> test = new List<Data>();
    test.Add(new Data { AValue = 25, BValue = 1.25, CValue = 99.99 });
    test.Add(new Data { AValue = 89, BValue = 2.10, CValue = 1.01 });
    test.Add(new Data { AValue = 10, BValue = 6, CValue = 45.45 });
    test.Add(new Data { AValue = 15, BValue = 2.33, CValue = 2.99 });
    test.Add(new Data { AValue = 90, BValue = 5.43, CValue = 27.89 });

    test.SetRanking(false, d => d.AValue, (d, i) => d.ARank = i);
    test.SetRanking(false, d => d.BValue, (d, i) => d.BRank = i);
    test.SetRanking(true, d => d.CValue, (d, i) => d.CRank = i);

最佳答案

未经测试,但类似这样:

void SetRanking(this List<Data> dataSet, Func<Data,int> getOrderBy, Action<Data,int> setRank)
{
    var ordered = dataSet.OrderBy(getOrderBy).ToArray();

    int i = i;
    foreach (Data item in ordered)
    {
        setRank(item, i);
        i++;
    }
}

RankingData.SetRanking(d => d.AValue, (d,i) => d.ARanking = i);
RankingData.SetRanking(d => d.BValue, (d,i) => d.BRanking = i);
RankingData.SetRanking(d => d.CValue, (d,i) => d.CRanking = i);

关于c# - 使用C#和LINQ处理排名数据,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/2389617/

10-13 08:11