使用linq分组经验总结

来源:互联网 发布:淘宝开店起步 编辑:程序博客网 时间:2024/06/11 20:41
声明实体类
  
public class NumericStockData    {        /// <summary>        /// 取值        /// </summary>        public double? Value { get; set; }          public NumericStockData()        {         }         public NumericStockData(DateTime time,string stockCode,double? value)        {            Time = time;            StockCode = stockCode;            Value = value;        }    } public partial class NumericStockDataList:List<NumericStockData>    {        public NumericStockDataList() : base() { }        public NumericStockDataList(IEnumerable<NumericStockData> linq) : base(linq) { }        public NumericStockDataList(int capacity) : base(capacity) { }    }


操作一:对一个集合StockList按照时间分组后,组内求均值,将此均值覆盖组内的每一项。返回每一项。

示例图:

第一步,按照时间点分组

 

日期

股票代码

收盘价

2014/01/25

000001

14.5

2014/01/25

000002

21.7

2014/01/26

000001

14.9

2014/01/26

000002

22.5

2014/01/27

000001

15.3

2014/01/27

000002

21.4

第二步:分组计算

日期

股票代码

收盘价

2014/01/25

000001

18.1

2014/01/25

000002

18.1

2014/01/26

000001

18.7

2014/01/26

000002

18.7

2014/01/27

000001

18.35

2014/01/27

000002

18.35

实现方法:

public static NumericStockDataList Gave1(NumericStockDataList StockList)        {            IEnumerable<NumericStockData> linq =                        from stock in StockList                        group stock by stock.Time into g//按时间分组                        let avg = g.Average(y => y.Value)//组均值                         from gstock in g                        select new NumericStockData()                        {                            Time = gstock.Time,                            StockCode = gstock.StockCode,                            Value = avg                                                   };            return new NumericStockDataList(linq);         }


操作二:

1. 按照日期进行分组

2. 分组按照排序要求 DESC对指标值进行排序

3. 分组填写排序结果,增加一列排名列。分组根据顺序填写排名顺序。

示例图:

RANK(现价, DESC

①      数据

 

股票代码

现价

 

6501

100

 

6502

200

 

6503

300

 

6504

400

 

6505

500

 

6506

700

 

6507

650

 

6508

300

 

 

②      降序排序

 

 

股票代码

现价

 

 

6506

700

 

 

6507

650

 

 

6505

500

 

 

6504

400

 

 

6503

300

 

 

6508

300

 

 

6502

200

 

 

6501

100

 

 

③    进行排名

 

 

股票代码

现价

排名

 

6506

700

1

 

6507

650

2

 

6505

500

3

 

6504

400

4

 

6503

300

5

 

6508

300

5

 

6502

200

7

 

6501

100

8

        

 

④      结果

 

股票代码

现价

结果

6501

100

8

6502

200

7

6503

300

5

6504

400

4

6505

500

3

6506

700

1

6507

650

2

6508

300

5














实现方法:

 
public static NumericStockDataList Rank(NumericStockDataList StockList)        {                  linq =   from stock in StockList                           group stock by stock.Time into g//按时间分组                            from gInside in g                           orderby gInside.Value ascending, gInside.Value.HasValue descending                           let gList = g.OrderByDescending(y => y.Value).ToList()//组内按值降序                            select new NumericStockData()                           {                               Time = gInside.Time,                               StockCode = gInside.StockCode,                               Value = (double?)gList.FindIndex(x => x.Value == gInside.Value) + 1,//按所在位置排名,若有重复取第一次出现的位置                           };                              return new NumericStockDataList(linq);  }
操作三:

1.  对成分股按照日期进行分组

2.  系统对股票指标值进行降序排序,

3.  新增一列,根据排序顺序填写排名

4.  对排名结果进行调整,具体规则为:指标值相同的,排名结果为相同指标值的排序做数值平均运算

5.  计算出各组排名的上下限数值

6.  将成分股排名数值与分组的排名数值上下限进行比较,对股票进行分组

示例图


QUANTILE(现价,NUMSTOCKS,5

<根据股票个数分组>

1.数据                     2.用现价降序排序,再排名

股票代码

现价

                   

 

现价

排名1

排名调整

6501

100

 

5000

1

1

6502

200

 

4500

2

2

6503

300

 

4200

3

3

6504

400

 

4000

4

4

6505

500

 

2000

5

5

6506

700

 

1000

6

6

6507

650

 

700

7

7.5

6508

300

 

700

8

7.5

6509

300

 

650

9

9.5

6510

400

 

650

10

9.5

6511

500

 

600

11

11.5

6512

700

 

600

12

11.5

6513

650

 

500

13

14

6514

300

 

500

14

14

6515

1000

 

500

15

14

6516

2000

 

400

16

17

6517

300

 

400

17

17

6518

4200

 

400

18

17

6519

4500

 

300

19

22

6520

600

 

300

20

22

6521

400

 

300

21

22

6522

5000

 

300

22

22

6523

4000

 

300

23

22

6524

600

 

300

24

22

6525

500

 

300

25

22

6526

300

 

200

26

26

6527

300

 

100

27

27

3.分组

每个组合的股票个数=股票数/分组数

每个组合的股票个数=27/5=5.4

 

下边线

上边线

排名

第1组

0

5.4

1

第2组

5.4

10.8

2

第3组

10.8

16.2

3

第4组

16.2

21.6

4

第5组

21.6

27

5

4.分位化

股票代码

现价

排名调整

结果

6522

5000

1

1

6519

4500

2

1

6518

4200

3

1

6523

4000

4

1

6516

2000

5

1

6515

1000

6

2

6506

700

7.5

2

6512

700

7.5

2

6507

650

9.5

2

6513

650

9.5

2

6520

600

11.5

3

6524

600

11.5

3

6505

500

14

3

6511

500

14

3

6525

500

14

3

6504

400

17

4

6510

400

17

4

6521

400

17

4

6503

300

22

5

6508

300

22

5

6509

300

22

5

6514

300

22

5

6517

300

22

5

6526

300

22

5

6527

300

22

5

6502

200

26

5

6501

100

27

5

实现方法:

 
 public static NumericStockDataList Quantile(NumericStockDataList StockList, string type, double nValue)        {  IEnumerable<NumericStockData> linq =                         from rankedList in                             (                              from stock in StockList.AddNullToBeMatrix()                              group stock by stock.Time into g//按时间分组                               let gList = g.OrderByDescending(x => x.Value).ToList()//现价降序                              let HasNull = g.Where(x => !x.Value.HasValue).Count() > 0                               from stockGroup in g                               let firstIndex = HasNull ? null : (double?)gList.FindIndex(x => x.Value == stockGroup.Value) + 1//相同值第一次出现的下标                              let lastIndex = HasNull ? null : (double?)gList.FindLastIndex((int)firstIndex - 1, x => x.Value == stockGroup.Value) + 1//相同值最后一次出现的下标                               let seperate = (double)g.Count() / n                              //排名:组内自然排序后,相同的值取排序值均值                              select new                              {                                  Time = stockGroup.Time,                                  StockCode = stockGroup.StockCode,                                  Value = firstIndex == null ? null : (double?)(firstIndex + lastIndex) / 2,//排名:当Value出现空值时,排名为空                                  Seperate = seperate,                                  IndustryIds = stockGroup.IndustryIds                              }                              )                         orderby rankedList.Value//按排名升序                          select new NumericStockData()                         {                             Time = rankedList.Time,                             StockCode = rankedList.StockCode,                             Value = rankedList.Value.HasValue ? System.Math.Ceiling((double)rankedList.Value / rankedList.Seperate) : rankedList.Value,//组号=排名/组数,向上取整;当排名为空时,组号为空                             IndustryIds = rankedList.IndustryIds                         };            return new NumericStockDataList(linq);}


总结:

1。这样理解分组的linq:分组后,每一组都是IEnumerable类型,可以对组内的项迭代。

迭代的方法即from x in xx。即可看作foreach(var x in xx)

2.巧用判断条件:

let:声明局部变量,其作用范围是嵌套在每个from x in xx之间。可以在此处设置判断条件

即:from x in xx

       let v=1;

      group x by x.Time into g

      from gInside in g

      let  y=2

     select {};

等价于  将xx分组后

    var v=1;

     foreach(var g in xx.GroupBy(i=>i.Tme))

{

 foreach(var gInside in g)

 {

  var y=2;

}

3。注意:对于大数据量(100000数量级以上),使用linq分组、筛选、排序的组合组度很慢。远不如for速度快,虽然写法极其优美。

0 0