1、多重分组列表生成逻辑

        这里来拆解一条较为复杂的多重列表生成哈,先放处理后的整句代码。

        var List = list.Where(p => p.P.mark3 != null)

                       .GroupBy(p => new { p.M.mark1,                                                                                                                                         p.M.mark2,                                                      

                                                        p.P.mark3 })

                      .Select(p => new { K = p.Key, data = p.ToList() })

                      .ToList();

1.1、Where字段进行数据筛选

        作用是过滤掉P.mark3里 为 null的记录,确保分组键的有效性。

1.2、GroupBy分组逻辑

        由mark1、mark2、mark3三个字段组成的分组键;如果某两条数据中这三个字段完全相同,则会被分到同一组内。

        举例:数据1:mark1=1;mark2=2;mark3=3;

                  数据2:mark1=1;mark2=2;mark3=3;

                  数据3:mark1=4;mark2=2;mark3=3;

                分组结果: K={1,2,3};data=【数据1、数据2】;

                                   K={4,2,3};data=【数据3】;

1.3、Select结果转换

        此处的 K 对应的就是上述处理的分组键(mark1+mark2+mark3);data则对应上述分组后该组的所有数据列表。

        举例:[ 

                       {

                          "K": { "mark1": 1, "mark2": 2, "mark3": 3 },

                          "data": [ { ...数据1... }, { ...数据2... } ]         

                        },

                      {

                          "K": { "mark1": 4, "mark2": 2, "mark3": 3 },

                          "data": [ { ...数据3... } ]                        

                        }

                    ]

1.4、 Tolist执行查询

        作用是立即执行查询,并将分组结果转换为 List,前面文章有提到不多累述。

1.5、小结

  源代码里仅对分组键其中之一有空值检查,如果其他两个也有空值则容易报错,除了源代码里的写法之外,也可以试着用空运算符?进行空值检查

   举例:

          var List = list.Where(p => p.P?.mark3 != null)

                             .GroupBy(p => new { p.M?.mark1,                                                                                                                                        p.M?.mark2,                                                      

                                                                p.P?.mark3 })

2、处理分组后的数据

老规矩,先上脱敏处理后的整片代码。

foreach (var plan in List)

        {

        Class1 X = new Class1();

        X.Month = begin;// 设置月份(begin为之前定义的起始时间)

        if (dict1.TryGetValue((double)plan.Key.mark3, out mark3ID quip))

         {

             X.Name1 = quip.Name;

             X.Code1 = quip.Code;

        } 

        if (dict2.TryGetValue((double)plan.Key.mark1, out mark1ID vat))

        {

                X.Name2 = vat.VatName;

                X.Code2 = vat.VatCode;

         }

        if (dict3.TryGetValue((double)plan.Key.mark2, out mark2ID ana))

         {         

                X.Name3 = ana.ProName;

        }

2.1、初始化对象和声明类型

        Class1 X = new Class1();

        X.Month = begin;// 设置月份(begin为之前定义的起始时间)

        这里的作用其实就是为每个分组创建一个新的统计结果对象,并记录时间范围。

        这里通过 new关键字调用构造函数,创建一个新的 Class1对象,对象的所有字段/属性被赋予默认值(如 string为 nullint为 0)。

        为什么X定义前面要放一个Class1而不是var呢,这个我查了下说是显示类型声明隐式类型推断的区别,显示类型声明一般用于团队协作的场景,减少类型推断的歧义。

2.2、查找与赋值

        if (dict1.TryGetValue((double)plan.Key.mark3, out mark3ID quip))

        针对这一句其实咋一看挺复杂,目的就是尝试从字典dict1查找键 (double)plan.Key.mark3。

    找得到的话就放回true进入if,并将对应的值赋给 quipout参数);

          如果找不着就会返回false跳过if,quip取得默认值。

        关于这个 out 好像也可以讲讲,在C#里,out用于指示参数按引用传递,且方法内部 ​​必须​​ 为 out参数赋值,out的好用之处在于它可以返回额外的信息不止于值。

后面还好多,不管先写到这发了。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐