• Pivot C# Array or DataTable: Convert a Column To a Row with LINQ(c#列转行)


    看看我

    My previous post explains how to convert a column to row in JavaScript array. In this post, we will do the same thing but with C# Array and DataTable using the power of LINQ or Lambda expression. For simplicity, I am using the same data.

    C# Array To Pivot DataTable

    1. Here is the C# array object:
    var data = new[] { 
                  new { Product = "Product 1", Year = 2009, Sales = 1212 },
                  new { Product = "Product 2", Year = 2009, Sales = 522 },
                  new { Product = "Product 1", Year = 2010, Sales = 1337 },
                  new { Product = "Product 2", Year = 2011, Sales = 711 },
                  new { Product = "Product 2", Year = 2012, Sales = 2245 },
                  new { Product = "Product 3", Year = 2012, Sales = 1000 }
              };
    
    1. On Googling, I found the following generic method in StackOverflow thread:
    public static DataTable ToPivotTable<T, TColumn, TRow, TData>(
        this IEnumerable<T> source,
        Func<T, TColumn> columnSelector,
        Expression<Func<T, TRow>> rowSelector,
        Func<IEnumerable<T>, TData> dataSelector)
            {
                DataTable table = new DataTable();
                var rowName = ((MemberExpression)rowSelector.Body).Member.Name;
                table.Columns.Add(new DataColumn(rowName));
                var columns = source.Select(columnSelector).Distinct();
     
                foreach (var column in columns)
                    table.Columns.Add(new DataColumn(column.ToString()));
     
                var rows = source.GroupBy(rowSelector.Compile())
                                 .Select(rowGroup => new
                                 {
                                     Key = rowGroup.Key,
                                     Values = columns.GroupJoin(
                                         rowGroup,
                                         c => c,
                                         r => columnSelector(r),
                                         (c, columnGroup) => dataSelector(columnGroup))
                                 });
     
                foreach (var row in rows)
                {
                    var dataRow = table.NewRow();
                    var items = row.Values.Cast<object>().ToList();
                    items.Insert(0, row.Key);
                    dataRow.ItemArray = items.ToArray();
                    table.Rows.Add(dataRow);
                }
     
                return table;
            }
    
    1. You can create a static class for extension methods and put it there.
      To convert Year values to columns and get Pivot DataTable:
    var pivotTable = data.ToPivotTable(
                  item => item.Year, 
                  item => item.Product,  
                  items => items.Any() ? items.Sum(x=>x.Sales) : 0);
    
    1. You will get the following output:

    C# Array to Pivot Dynamic Array

    1. You might want to get the List or dynamic[] instead of getting DataTable after converting columns to rows. It is handy in ASP.NET Web API to return JSON response.
    2. To do it, I updated the extension method to get the dynamic object. use following extension method:
    public static dynamic[] ToPivotArray<T, TColumn, TRow, TData>(
    this IEnumerable<T> source,
    Func<T, TColumn> columnSelector,
    Expression<Func<T, TRow>> rowSelector,
    Func<IEnumerable<T>, TData> dataSelector)
           {
     
               var arr = new List<object>();
               var cols = new List<string>();
               String rowName = ((MemberExpression)rowSelector.Body).Member.Name;
               var columns = source.Select(columnSelector).Distinct();       
     
               cols =(new []{ rowName}).Concat(columns.Select(x=>x.ToString())).ToList();
     
     
               var rows = source.GroupBy(rowSelector.Compile())
                                .Select(rowGroup => new
                                {
                                    Key = rowGroup.Key,
                                    Values = columns.GroupJoin(
                                        rowGroup,
                                        c => c,
                                        r => columnSelector(r),
                                        (c, columnGroup) => dataSelector(columnGroup))
                                }).ToArray();
     
     
               foreach (var row in rows)
               {
                   var items = row.Values.Cast<object>().ToList();
                   items.Insert(0, row.Key);
                   var obj = GetAnonymousObject(cols, items);
                   arr.Add(obj);               
               }
               return arr.ToArray();
           }
     private static dynamic GetAnonymousObject(IEnumerable<string> columns, IEnumerable<object> values)
           {
               IDictionary<string, object> eo = new ExpandoObject() as IDictionary<string, object>;
               int i;
               for (i = 0; i < columns.Count(); i++)
               {
                   eo.Add(columns.ElementAt<string>(i), values.ElementAt<object>(i));
               }
               return eo;
           }
    
    1. ExpandoObject is used to create dynamic object.
      Now, to convert row to column and get dynamic array:
    var pivotArray = data.ToPivotArray(
                    item => item.Year,
                   item => item.Product,
                   items => items.Any() ? items.Sum(x => x.Sales) : 0);
    
    1. You can easily convert in JSON format
    String json = JsonConvert.SerializeObject(pivotArray, new KeyValuePairConverter());
    
    1. Here is the result:

    C# DataTable to Pivot DataTable

    1. Let us have a DataTable with same data:
    DataTable myDataTable = new DataTable();
    myDataTable.Columns.AddRange(new DataColumn[3] { new DataColumn("Product"), new DataColumn("Year", typeof(int)), new DataColumn("Sales", typeof(int)) });
    myDataTable.Rows.Add("Product 1", 2009, 1212);
    myDataTable.Rows.Add("Product 2", 2009, 522);
    myDataTable.Rows.Add("Product 1", 2010, 1337);
    myDataTable.Rows.Add("Product 2", 2011, 711);
    myDataTable.Rows.Add("Product 2", 2012, 2245);
    myDataTable.Rows.Add("Product 3", 2012, 1000);
    
    1. You can use the same extension method to get Pivot DataTable like below.
    var data2 = myDataTable.AsEnumerable().Select(x=> new { 
                   Product =x.Field<String>("Product"), 
                   Year= x.Field<int>("Year"), 
                   Sales = x.Field<int>("Sales") });
               
               DataTable pivotDataTable =data2.ToPivotTable(
                    item => item.Year,
                   item => item.Product,
                   items => items.Any() ? items.Sum(x => x.Sales) : 0);
    
    1. Here is the result:

    DataTable to List

    1. If you need to convert DataTable to List of dynamic object then use following extension method:
    public static List<dynamic> ToDynamicList(this DataTable dt)
           {
               var list = new List<dynamic>();
               foreach (DataRow row in dt.Rows)
               {
                   dynamic dyn = new ExpandoObject();
                   list.Add(dyn);
                   foreach (DataColumn column in dt.Columns)
                   {
                       var dic = (IDictionary<string, object>)dyn;
                       dic[column.ColumnName] = row[column];
                   }
               }
               return list;
           }
    
    1. Here is the result:

    Conclusion

    In this post, we played with C# Array, DataTable and implemented to convert row to column and get Pivot Array, DataTable and List of dynamic object.

    Hope, It helps.

  • 相关阅读:
    ASP.NET MVC4.0+EF+LINQ+bui+bootstrap+网站+角色权限管理系统(2)
    ASP.NET MVC4.0+EF+LINQ+bui+bootstrap+网站+角色权限管理系统(1)
    ASP.NET MVC4.0+EF+LINQ+bui+bootstrap+网站+角色权限管理系统(开篇)
    时间文本框,入职时间,工龄的换算
    javascript中this的用法
    web的Tomcat8部署文档
    rabbitMQ集群安装部署
    Python实现统计Jenkins multibranch发布的分支及时间等 页面 … 部署文档 跳到banner的尾部 回到标题开始 转至元数据结尾
    centos 7 DNS部署
    MongoDB3.X参数文件
  • 原文地址:https://www.cnblogs.com/vvull/p/14744925.html
Copyright © 2020-2023  润新知