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.

1|0C# 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:

2|0C# 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:

3|0C# 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:

4|0DataTable 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:

5|0Conclusion

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.


__EOF__

本文作者vvull
本文链接https://www.cnblogs.com/vvull/p/14744925.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   vvull  阅读(1315)  评论(1编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
点击右上角即可分享
微信分享提示