代码之家  ›  专栏  ›  技术社区  ›  thaBadDawg

处理排名数据w/C#&LINQ

  •  2
  • thaBadDawg  · 技术社区  · 16 年前

    我在一个列表中有一个对象,我需要用几种不同的方式对它进行排序。目前的代码是相当笨拙的,因为它需要我单独处理每一列。例子:

    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++;
        }
    }
    

    更新

    以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);
    
    3 回复  |  直到 16 年前
        1
  •  1
  •   Tanzelax    16 年前

    没有测试过,但类似这样:

    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);
    
        2
  •  1
  •   DRBlaise    16 年前

    这与Tanzelax的答案相似,但是一种通用的扩展方法。

    public static void RankData<TSource, TKey>(
        this IEnumerable<TSource> source,
        Func<TSource, TKey> keySelector,
        Action<TSource, int> rankSetter
    )
    {
        int count = 1;
        foreach (var item in source.OrderBy(keySelector))
        {
            rankSetter(item, count);
            ++count;
        }
    }
    

    RankingData.RankData(d => d.AValue, (d,i) => d.ARanking = i);
    
        3
  •  0
  •   tvanfosson    16 年前

    通过 Func<Data,K> 返回排名键。K应该实现IComparable

    public static void Rank<K>( IEnumerable<Data> source, Func<Data,K> rankBy ) where K : IComparable
    {
       int count = 1;
       foreach (var item in source.OrderBy( rankBy ))
       {
           item.R = count;
           ++count;
       }
    }