【问题标题】:Pivoting multiple columns in C#在 C# 中旋转多个列
【发布时间】:2016-08-22 17:15:24
【问题描述】:

我有一个需要旋转和转换的对象的 C# 列表。但我不确定如何获得预期的结果。下面的代码讨论了结构、数据和期望的结果。我知道,我需要先对数据进行分组,然后再对其进行透视。但我很困惑如何实现它。

class Program
{
    static void Main(string[] args)
    {
        List<Rev> revList = new List<Rev>();
        Rev r = new Rev { Id = 1, Name = "One", Rank = 1, Region = "Global", Revenue = 600 }; revList.Add(r);
        r = new Rev { Id = 1, Name = "One", Rank = 1, Region = "USA", Revenue = 100 }; revList.Add(r);
        r = new Rev { Id = 1, Name = "One", Rank = 1, Region = "Euro", Revenue = 200 }; revList.Add(r);
        r = new Rev { Id = 1, Name = "One", Rank = 1, Region = "APAC", Revenue = 300 }; revList.Add(r);

        r = new Rev { Id = 2, Name = "Two", Rank = 2, Region = "Global", Revenue = 500 }; revList.Add(r);
        r = new Rev { Id = 2, Name = "Two", Rank = 2, Region = "USA", Revenue = 100 }; revList.Add(r);
        r = new Rev { Id = 2, Name = "Two", Rank = 3, Region = "APAC", Revenue = 400 }; revList.Add(r);

        r = new Rev { Id = 3, Name = "Three", Rank = 2, Region = "Global", Revenue = 300 }; revList.Add(r);
        r = new Rev { Id = 3, Name = "Three", Rank = 2, Region = "USA", Revenue = 100 }; revList.Add(r);
        r = new Rev { Id = 3, Name = "Three", Rank = 3, Region = "Euro", Revenue = 200 }; revList.Add(r);

        //Should result in THIS IS THE HARD CODED RESULT WHICH TRANFORM FUNCTION SHOULD GENERATE
        List<RevExtended> resultList = new List<RevExtended>();
        RevExtended res = new RevExtended{Name = "One", Id = 1, APACRevenue = 300, ApacRank = 1, EuroRank = 1, EurpRevenue = 200, GlobalRank = 1, GlobalRevenue = 600, USARank = 1, USARevenue = 100};
        res = new RevExtended { Name = "Two", Id = 2, APACRevenue = 400, ApacRank = 3, GlobalRank = 2, GlobalRevenue = 500, USARank = 2, USARevenue = 100 };
        res = new RevExtended { Name = "Three", Id = 3, EuroRank = 3, EurpRevenue = 200, GlobalRank = 2, GlobalRevenue = 300, USARank = 2, USARevenue = 100 };
    }

    public List<RevExtended> Transform(List<Rev> revList)
    {
        List<RevExtended> resultList = new List<RevExtended>();

        var query = from rev in revList
                    group rev by rev.Id into revGroup


        return resultList;
    }
}

public class Rev
{
    public string Name { get; set; }
    public int Id { get; set; }
    public int? Revenue { get; set; }
    public int? Rank { get; set; }
    public string Region { get; set; }
}

public class RevExtended
{
    public string Name { get; set; }
    public int Id { get; set; }

    public int? GlobalRevenue { get; set; }
    public int? GlobalRank { get; set; }

    public int? USARevenue { get; set; }
    public int? USARank { get; set; }

    public int? EurpRevenue { get; set; }
    public int? EuroRank { get; set; }

    public int? APACRevenue { get; set; }
    public int? ApacRank { get; set; }
}

【问题讨论】:

    标签: c# .net linq c#-4.0 pivot


    【解决方案1】:

    这是您可以采取的一种方法:

    var pivoted =
        from d in data
        group d by new { d.Id, d.Name } into region
        let g = region.SingleOrDefault(d => d.Region == "Global") ?? new Rev()
        let u = region.SingleOrDefault(d => d.Region == "USA") ?? new Rev()
        let e = region.SingleOrDefault(d => d.Region == "Euro") ?? new Rev()
        let a = region.SingleOrDefault(d => d.Region == "APAC") ?? new Rev()
        select new RevExtended
        {
            Id = region.Key.Id,
            Name = region.Key.Name,
            GlobalRevenue = g.Revenue,
            GlobalRank = g.Rank,
            UsaRevenue = u.Revenue,
            UsaRank = u.Rank,
            EuroRevenue = e.Revenue,
            EuroRank = e.Rank,
            ApacRevenue = a.Revenue,
            ApacRank = a.Rank,
        };
    

    如果您需要null 值而没有区域,则需要更改模型以支持它们。

    public class RevExtended
    {
        public int Id { get; set; }
        public string Name { get; set; }
    
        public int? GlobalRank { get; set; }
        public int? GlobalRevenue { get; set; }
    
        public int? UsaRank { get; set; }
        public int? UsaRevenue { get; set; }
    
        public int? EuroRank { get; set; }
        public int? EuroRevenue { get; set; }
    
        public int? ApacRank { get; set; }
        public int? ApacRevenue { get; set; }
    }
    
    var pivoted =
        from d in data
        group d by new { d.Id, d.Name } into region
        let g = region.SingleOrDefault(d => d.Region == "Global")
        let u = region.SingleOrDefault(d => d.Region == "USA")
        let e = region.SingleOrDefault(d => d.Region == "Euro")
        let a = region.SingleOrDefault(d => d.Region == "APAC")
        select new RevExtended
        {
            Id = region.Key.Id,
            Name = region.Key.Name,
            GlobalRevenue = g?.Revenue,
            GlobalRank = g?.Rank,
            UsaRevenue = u?.Revenue,
            UsaRank = u?.Rank,
            EuroRevenue = e?.Revenue,
            EuroRank = e?.Rank,
            ApacRevenue = a?.Revenue,
            ApacRank = a?.Rank,
        };
    

    【讨论】:

    • 感谢您的快速帮助。这很棒。当Rank或recomment在任何地区都不可用时,目前显示为0,如何设置为null?
    • @OpenStack 从所有let 行中删除?? new Rev(),然后在select 内使用g?.Revenueg?.Rank 等。
    【解决方案2】:

    当您不使用 C# 6.0 时

    var pivoted =
        from x in revList.ToLookup(d => new { d.Id, d.Name })
        let g = x.SingleOrDefault(d => d.Region == "Global") ?? new Rev()
        let u = x.SingleOrDefault(d => d.Region == "USA") ?? new Rev()
        let e = x.SingleOrDefault(d => d.Region == "Euro") ?? new Rev()
        let a = x.SingleOrDefault(d => d.Region == "APAC") ?? new Rev()
        select new RevExtended
        {
            Id = x.Key.Id,
            Name = x.Key.Name,
            GlobalRevenue = g.Revenue == null ? null : g.Revenue,
            GlobalRank = g.Rank == null ? null : g.Rank,
            USARevenue = u.Revenue == null ? null : u.Revenue,
            USARank = u.Rank == null ? null : u.Rank,
            EuroRevenue = e.Revenue == null ? null: e.Revenue,
            EuroRank = e.Rank == null ? null : e.Rank,
            ApacRevenue = a.Revenue == null ? null : a.Revenue,
            ApacRank = a.Rank == null ? null : a.Rank,
        };
    

    【讨论】:

      【解决方案3】:

      @OpenStack,根据接受的答案的最后一部分,您有一个适用于 6.0 之前的 C# 用户的答案。你的例子不太对。有两个问题:

      • 您的示例将始终有一个 Rev 对象,因此该对象引用 永远不会为空。
      • 如果您确实允许空值(如预期的那样),则分配逻辑不会保护您免受空值的影响。

      这是 6.0 之前的 C# 版本的公认答案的等价物:

      var pivoted =
          from x in revList.ToLookup(d => new { d.Id, d.Name })
          let g = x.SingleOrDefault(d => d.Region == "Global") 
          let u = x.SingleOrDefault(d => d.Region == "USA")
          let e = x.SingleOrDefault(d => d.Region == "Euro")
          let a = x.SingleOrDefault(d => d.Region == "APAC")
          select new RevExtended
          {
              Id = x.Key.Id,
              Name = x.Key.Name,
              GlobalRevenue = g == null ? null : g.Revenue,
              GlobalRank = g == null ? null : g.Rank,
              USARevenue = u == null ? null : u.Revenue,
              USARank = u == null ? null : u.Rank,
              EuroRevenue = e == null ? null: e.Revenue,
              EuroRank = e == null ? null : e.Rank,
              ApacRevenue = a == null ? null : a.Revenue,
              ApacRank = a == null ? null : a.Rank,
          };    
      

      如果您同意,您可以更新您的答案,使其正确无误(如果您愿意,可以复制并粘贴我的答案),我将删除此答案。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-05-06
        • 1970-01-01
        • 2014-07-26
        • 2021-08-11
        • 2017-04-24
        • 1970-01-01
        • 1970-01-01
        • 2019-11-30
        相关资源
        最近更新 更多