繁体   English   中英

C#:按类型,年,月分组/分组付款

[英]C#: Grouping/Subgrouping Payment By Type, Year, Month

我正在执行“付款报告”,并始终将我的头靠在墙上。 后端是SQL Server,付款表设置为:

PaymentId |    Date    |  Type  | Misc Fields
0          2000-08-10    cash     ...
25         2019-08-05    web CC   ...
26         2019-08-05    cash     ...
27         2019-08-05    cash     ...
28         2019-08-05    check    ...
29         2019-07-10    cash     ...

我正在尝试使用C#的LINQ读取Payment表,然后应用分组; 这样结果就可以分为以下几类:

  • 1级:类型
  • 2级:PaymentDate.Year
  • 第三级:PaymentDate.Month
cash
   2000
      08
         Payment 0 Details
   2019
      07
         Payment 29 Details
      08
         Payment 26
         Payment 27
check
   2019
      08
         Payment 28
web CC
   2019
      08
         Payment 25

我尝试了几种方法,但是我得到的最接近的方法是按类型/月或类型/年分组。

我偶然发现(没有开玩笑的意思) 女士的创建嵌套小组

这是我尝试基于以下代码(类型/月份分组的结果)的基础:

var ranges = new List<String> { "Cash", "Check", "Money Order", "Web CC" };

var groupedPayments = from payment in allPayments
                                  let match = ranges.FirstOrDefault(range => range.Equals(payment.PaymentType, StringComparison.OrdinalIgnoreCase))
                                  group payment by !String.IsNullOrEmpty(match) ? match : "Other" into TypeBracket
                                  from payment2 in (
                                       from pay in TypeBracket
                                       group pay by pay.PaymentDate.Year into TypedYearBracket
                                       from payment3 in (
                                           from pay2 in TypedYearBracket
                                           group pay2 by pay2.PaymentDate.Month into MonthBracket
                                           select MonthBracket
                                       )
                                       select payment3
                                  )
                                  group payment2 by TypeBracket.Key;

控制台应用程序的简化代码

付款类别定义

public class Payment 
{
    public int PaymentId { get; set; }
        public DateTime PaymentDate { get; set; }
        public String PaymentType { get; set; }

        public Payment(int id, DateTime date, string type)
        {
            PaymentId = id;
            PaymentDate = date;
            PaymentType = type;
        }
}

主要

public class PaymentExample 
{
    private static void Main(string[] args)
        {
            List<Payment> allPayments = new List<Payment>()
            {
                new Payment(25, new DateTime(2019, 8, 5), "web CC"),
                new Payment(26, new DateTime(2019, 8, 5), "cash"),
                new Payment(27, new DateTime(2019, 8, 5), "cash"),
                new Payment(28, new DateTime(2019, 8, 5), "check"),
                new Payment(29, new DateTime(2019, 7, 10), "cash"),
                new Payment(0, new DateTime(2000, 8, 10), "cash")
            };

            var ranges = new List<String> { "Cash", "Check", "Money Order", "Web CC" };

            var groupedPayments = from payment in allPayments
                                  let match = ranges.FirstOrDefault(range => range.Equals(payment.PaymentType, StringComparison.OrdinalIgnoreCase))
                                  group payment by !String.IsNullOrEmpty(match) ? match : "Other" into TypeBracket
                                  from payment2 in (
                                       from pay in TypeBracket
                                       group pay by pay.PaymentDate.Year into TypedYearBracket
                                       from payment3 in (
                                           from pay2 in TypedYearBracket
                                           group pay2 by pay2.PaymentDate.Month into MonthBracket
                                           select MonthBracket
                                       )
                                       select payment3
                                  )
                                  group payment2 by TypeBracket.Key;

            Console.WriteLine("Hello World!");// Note I'm checking the output by using a breakpoint on this line. However, I can add further code if necessary
        }
}

***对jdweng的帖子发表评论太久了
嗯,我想我丢失了一些东西。 我加了

foreach (var x in results)
            {
                foreach (var y in x)
                {
                    Console.WriteLine("Type: {0}, Year: {1}, Month: {2}, ID: {3}", y.PaymentType, y.PaymentDate.Year, y.PaymentDate.Month, y.PaymentId);
                }

            }

到主要功能的末尾,看看打印了什么。 它似乎是按匿名类型{type,month}分组的,但结果是

Type: web CC, Year: 2019, Month: 8, ID: 25
Type: cash, Year: 2019, Month: 8, ID: 26
Type: cash, Year: 2019, Month: 8, ID: 27
Type: check, Year: 2019, Month: 8, ID: 28
Type: cash, Year: 2019, Month: 7, ID: 29

注意:这些类型不会组合在一起,并且会完全忽略年份(在最初的示例中毫无意义,但实际数据集包含的日期可以追溯到2000年),我对其进行了更新,以显示在2000年付款的示例

我想我解决了! 这可能是我在这里自己设置的特定功能,但我认为我将与可能偶然遇到此问题的任何人共享该解决方案。 首先,我要感谢jdweng给我一些时间,并感谢所有看过它的人,并且可能在此刻正在努力! 如果您发现我的答案有问题(或可以改善); 请随便发表评论或发表自己的答案!

看了一会儿(太长了,哈哈),我意识到

   from payment3 in (
      from pay2 in TypedYearBracket
      group pay2 by pay2.PaymentDate.Month into MonthBracket
      select MonthBracket
   )
   select payment3

造成分组问题,并且几乎抹去了我按年份分组的尝试。

然后,我意识到整个LINQ部分的最后一个分组( group payment2 by TypeBracket.Key;正在将Type分组重新应用于内部组的结果。这使我意识到,代替select payment3 ;我需要group payment3 by TypedYearBracket.Key ,将Year分组重新应用于Month子分组结果。

最终生成代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            List<Payment> allPayments = new List<Payment>()
            {
                new Payment(25, new DateTime(2019, 8, 5), "web CC"),
                new Payment(26, new DateTime(2019, 8, 5), "cash"),
                new Payment(27, new DateTime(2019, 8, 5), "cash"),
                new Payment(28, new DateTime(2019, 8, 5), "check"),
                new Payment(29, new DateTime(2019, 7, 10), "cash"),
                new Payment(0, new DateTime(2000, 8, 10), "cash")
            };

           var ranges = new List<String> { "Cash", "Check", "Money Order", "Web CC" };

           var results = from payment in allPayments
                         let match = ranges.FirstOrDefault(range => range.Equals(payment.PaymentType, StringComparison.OrdinalIgnoreCase))
                         group payment by !String.IsNullOrEmpty(match) ? match : "Other" into TypeBracket
                         from payment2 in (
                            from pay in TypeBracket
                            group pay by pay.PaymentDate.Year into TypedYearBracket
                            from payment3 in (
                                  from pay2 in TypedYearBracket
                                  group pay2 by pay2.PaymentDate.Month into MonthBracket
                                  select MonthBracket
                            )
                            group payment3 by TypedYearBracket.Key
                         )
                         group payment2 by TypeBracket.Key;
            foreach (var x in results)
            {
                Console.WriteLine("1st Level: {0} - {1}", x.Key, x.Count());
                foreach (var y in x)
                {
                    Console.WriteLine("   2nd Level: {0} - {1}", y.Key, y.Count());
                    foreach (var z in y)
                    {
                        Console.WriteLine("      3rd Level: {0} - {1}", z.Key, z.Count());
                        foreach (var a in z)
                        {
                            Console.WriteLine("         Details: Type: {0}, Year: {1}, Month: {2}, ID: {3}", a.PaymentType, a.PaymentDate.Year, a.PaymentDate.Month, a.PaymentId);
                        }

                    }
                }
        }
    }
    public class Payment
    {
        public int PaymentId { get; set; }
        public DateTime PaymentDate { get; set; }
        public String PaymentType { get; set; }

        public Payment(int id, DateTime date, string type)
        {
            PaymentId = id;
            PaymentDate = date;
            PaymentType = type;
        }
    }
}

这给出了预期的结果:

1st Level: Web CC - 1
   2nd Level: 2019 - 1
      3rd Level: 8 - 1
         Details: Type: web CC, Year: 2019, Month: 8, ID: 25
1st Level: Cash - 2
   2nd Level: 2019 - 2
      3rd Level: 8 - 2
         Details: Type: cash, Year: 2019, Month: 8, ID: 26
         Details: Type: cash, Year: 2019, Month: 8, ID: 27
      3rd Level: 7 - 1
         Details: Type: cash, Year: 2019, Month: 7, ID: 29
   2nd Level: 2000 - 1
      3rd Level: 8 - 1
         Details: Type: cash, Year: 2000, Month: 8, ID: 0
1st Level: Check - 1
   2nd Level: 2019 - 1
      3rd Level: 8 - 1
         Details: Type: check, Year: 2019, Month: 8, ID: 28

请尝试以下。 图片显示为“现金”而非“类型”:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            List<string> order = new List<string>() {"web CC", "cash", "check"};


            List<Payment> allPayments = new List<Payment>()
            {
                new Payment(25, new DateTime(2019, 8, 5), "web CC"),
                new Payment(26, new DateTime(2019, 8, 5), "cash"),
                new Payment(27, new DateTime(2019, 8, 5), "cash"),
                new Payment(28, new DateTime(2019, 8, 5), "check"),
                new Payment(29, new DateTime(2019, 7, 10), "cash")
            };


            var groups = allPayments
                .OrderBy(x => order.IndexOf(x.PaymentType))
                .ThenByDescending(x => x.PaymentDate)
                .GroupBy(x => new { type = x.PaymentType, month = new DateTime(x.PaymentDate.Year, x.PaymentDate.Month, 1) })
                .ToList();

            foreach(var group in groups)
            {
                foreach(Payment payment in group)
                {
                    Console.WriteLine("Type : '{0}', Year : {1}, Month : '{2}', Id : '{3}'", payment.PaymentType, payment.PaymentDate.Year.ToString(), payment.PaymentDate.Month.ToString(), payment.PaymentId);
                }
            }


        }
    }
    public class Payment
    {
        public int PaymentId { get; set; }
        public DateTime PaymentDate { get; set; }
        public String PaymentType { get; set; }

        public Payment(int id, DateTime date, string type)
        {
            PaymentId = id;
            PaymentDate = date;
            PaymentType = type;
        }
    }
}

在此处输入图片说明

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM