Using Linq to GroupBy and Sum datatable
You can GroupBy
first, then project the groups to DataRow
s, then create the DataTable
using CopyToDataTable
extension:
var newDt = dt.AsEnumerable()
.GroupBy(r => r.Field<int>("Id"))
.Select(g =>
{
var row = dt.NewRow();
row["Id"] = g.Key;
row["Amount 1"] = g.Sum(r => r.Field<int>("Amount 1"));
row["Amount 2"] = g.Sum(r => r.Field<int>("Amount 2"));
row["Amount 3"] = g.Sum(r => r.Field<int>("Amount 3"));
return row;
}).CopyToDataTable();
Using Linq to GroupBy and Sum datatable
You can GroupBy
first, then project the groups to DataRow
s, then create the DataTable
using CopyToDataTable
extension:
var newDt = dt.AsEnumerable()
.GroupBy(r => r.Field<int>("Id"))
.Select(g =>
{
var row = dt.NewRow();
row["Id"] = g.Key;
row["Amount 1"] = g.Sum(r => r.Field<int>("Amount 1"));
row["Amount 2"] = g.Sum(r => r.Field<int>("Amount 2"));
row["Amount 3"] = g.Sum(r => r.Field<int>("Amount 3"));
return row;
}).CopyToDataTable();
Group and Sum DataTable
rgoal
Your question made me curious, so I did some digging on Stack Overflow.
esc's answer appears will also solve your issue. It is posted under: How do I use SELECT GROUP BY in DataTable.Select(Expression)?:
Applying his method to your problem gave me this solution:
DataTable dt2 = dt.AsEnumerable()
.GroupBy(r => new { Number = r["Number"], Type = r["Type"], Order = r["Order"] })
.Select(g =>
{
var row = dt.NewRow();
row["Number"] = g.Key.Number;
row["Type"] = g.Key.Type;
row["Order"] = g.Key.Order;
row["Count"] = g.Count();
return row;
}).CopyToDataTable();
This will return a DataTable matching the schema of the input DataTable with the grouping and counts you requested.
Here is the full code I use to verify in LINQPad:
DataTable dt = new DataTable("Demo");
dt.Columns.AddRange
(
new DataColumn[]
{
new DataColumn ( "Number", typeof ( int ) ),
new DataColumn ( "Type", typeof ( int ) ),
new DataColumn ( "Order", typeof ( string ) ),
new DataColumn ( "Count", typeof ( int ) )
}
);
dt.Rows.Add(new object[] { 1,1,"R", 1 });
dt.Rows.Add(new object[] { 1,1,"R", 1 });
dt.Rows.Add(new object[] { 1,1,"R", 1 });
dt.Rows.Add(new object[] { 1,2,"R", 1 });
DataTable dt2 = dt.AsEnumerable()
.GroupBy(r => new { Number = r["Number"], Type = r["Type"], Order = r["Order"] })
.Select(g =>
{
var row = dt.NewRow();
row["Number"] = g.Key.Number;
row["Type"] = g.Key.Type;
row["Order"] = g.Key.Order;
row["Count"] = g.Count();
return row;
}).CopyToDataTable();
foreach (DataRow row in dt2.Rows)
{
for (int i = 0; i < dt2.Columns.Count; i++)
Console.Write("{0}{1}",
row[i], // Print column data
(i < dt2.Columns.Count - 1)? " " : Environment.NewLine); // Print column or row separator
}
Here are the results:
1 1 R 3
1 2 R 1
Convert Datatable GroupBy Multiple Columns with Sum using Linq
You can use this:-
DataTable countriesTable = dt.AsEnumerable().GroupBy(x => new { CountryId = x.Field<int>("CountryId"), CityId = x.Field<int>("CityId") })
.Select(x => new Countries
{
CountryId = x.Key.CountryId,
CityId = x.Key.CityId,
TotalSum = x.Sum(z => z.Field<int>("TotalImages"))
}).PropertiesToDataTable<Countries>();
I am getting, following output:-
Since, We cannot use CopyToDataTable
method for anonymous types, I have used an extension method took from here and modified it accordingly.
public static DataTable PropertiesToDataTable<T>(this IEnumerable<T> source)
{
DataTable dt = new DataTable();
var props = TypeDescriptor.GetProperties(typeof(T));
foreach (PropertyDescriptor prop in props)
{
DataColumn dc = dt.Columns.Add(prop.Name, prop.PropertyType);
dc.Caption = prop.DisplayName;
dc.ReadOnly = prop.IsReadOnly;
}
foreach (T item in source)
{
DataRow dr = dt.NewRow();
foreach (PropertyDescriptor prop in props)
{
dr[prop.Name] = prop.GetValue(item);
}
dt.Rows.Add(dr);
}
return dt;
}
And, here is the Countries
type:-
public class Countries
{
public int CountryId { get; set; }
public int CityId { get; set; }
public int TotalSum { get; set; }
}
You can use any other approach to convert it to a DataTable if you wish.
Datatable group by sum
table1.AsEnumerable().Concat(table2.AsEnumerable())
.GroupBy(r => r.Field<string>("Name"))
.Select(g => new {
Name = g.Key,
Rank1 = g.Count(x => x.Field<int>("Rank") == 1),
Rank2 = g.Count(x => x.Field<int>("Rank") == 2),
Rank3 = g.Count(x => x.Field<int>("Rank") == 3),
OtherRank = g.Count(x => x.Field<int>("Rank") > 3)
}).CopyToDataTable();
You will need implementation of CopyToDataTable method where Generic Type T Is Not a DataRow.
A little optimized solution (single parsing and single loop over grouped ranks):
(from row in table1.AsEnumerable().Concat(table2.AsEnumerable())
group row by row.Field<string>("Name") into g
let ranks = g.Select(x => x.Field<int>("Rank")).ToList()
select new {
Name = g.Key,
Rank1 = ranks.Count(r => r == 1),
Rank2 = ranks.Count(r => r == 2),
Rank3 = ranks.Count(r => r == 3),
OtherRank = ranks.Count(r => r > 3)
}).CopyToDataTable();
c# datatable groupby and sum column's values (without know the name)
So assuming you have at least the list of column names, I'd go with the approach of creating a dictionary as part of the select and then transform it later to whatever form you need it. Here's an example:
var query = from stat in stats
group stat by stat.Field<string>("Data") into data
orderby data.Key
select new
{
Data = data.Key,
SumsDictionary = listOfColumnNames
.Select(colName => new { ColName = colName, Sum = data.Sum(stat => stat.Field<int>(colName)) })
.ToDictionary(d => d.ColName, d => d.Sum),
Productivity = 0,
};
So that if you were to serialize the result object it would look something like this:
{
"Data": {},
"SumsDictionary": {
"Time_Work": 10,
"Time_Hold": 20,
"Time_Alarm": 30
},
"Productivity": 0
}
Hope it helps!
C# Datatable group, select and sum
If the fixed salary is always the same for the Name, you can use this :
var result = from tab in dtTemp.AsEnumerable()
group tab by tab["Name"]
into groupDt
select new
{
Agent = groupDt.Key,
Commision = groupDt.Sum((r) => decimal.Parse(r["Amount"].ToString())),
FixedSalary = groupDt.Select(r => r["FixedSalary"].ToString()).FirstOrDeafult()
};
İf it can be change, you should group it with the name column.
c# DataTable Linq Group by Multiple column sum int and timespan
You have to Parse the TimeSpan
and Sum
by using Ticks
, like below.
var Temp_DT = tempdt.AsEnumerable().Select(x =>
new
{
UID = x["UID"],
EMPNAME = x["Emp Name"],
EMPROLE = x["Role"],
SUPID = x["Sup ID"],
SUPNAME = x["Sup Name"],
DESIGNATION = x["Designation"],
VOLUME = x["Volume"],
ERRORTIME = x["Error_Time"],
ACWTIME = x["ACW"],
BREAKTIME = x["Break Time"],
IDLETIME = x["Idle"],
NONPRODUCTIVE = x["Non Productive"],
}).GroupBy(s => new { s.UID, s.EMPNAME, s.EMPROLE, s.SUPID, s.SUPNAME, s.DESIGNATION })
.Select(g => {
var grouped = g.ToList();
return new
{
UID = g.Key.UID,
EMPNAME = g.Key.EMPNAME,
EMPROLE = g.Key.EMPROLE,
SUPID = g.Key.SUPID,
SUPNAME = g.Key.SUPNAME,
DESIGNATION = g.Key.DESIGNATION,
VOLUME = grouped.Sum(x => Convert.ToInt16(x.VOLUME)),
Error_Time = new TimeSpan(grouped.Select(x => ConvertTimeSpan(x.ERRORTIME.ToString())).ToList().Sum(r=> r.Ticks)),
ACW = new TimeSpan(grouped.Select(x => ConvertTimeSpan(x.ACWTIME.ToString())).ToList().Sum(r=> r.Ticks)),
Break = new TimeSpan(grouped.Select(x => ConvertTimeSpan(x.BREAKTIME.ToString())).ToList().Sum(r=> r.Ticks)),
Idle = new TimeSpan(grouped.Select(x => ConvertTimeSpan(x.IDLETIME.ToString())).ToList().Sum(r=> r.Ticks)),
NonProductive = new TimeSpan(grouped.Select(x => ConvertTimeSpan(x.NONPRODUCTIVE.ToString())).ToList().Sum(r=> r.Ticks))
};
}).ToList();
The Conversion method is,
private static TimeSpan ConvertTimeSpan(string str)
{
TimeSpan outputValue;
TimeSpan.TryParse(str, out outputValue);
return outputValue;
}
C# Fiddle with sample data.
Related Topics
Make a File Open in Browser Instead of Downloading It
How to Correctly Write Parallel.For With Async Methods
Pass Array into ASP.NET Core Route Query String
Using Linq to Groupby and Sum Datatable
Sorting a Collection Containing Strings And/Or Numbers
Asp.Net Core 2 Web API Timeout Issue
How to Save Mailmessage Object to Disk as *.Eml or *.Msg File
Instantiating an Iformfile from a Physical File
How to Get the Specific Column in Excel Worksheet Using Documentformat.Openxml C#
C# Multipart/Form-Data Submit Programmatically
Reload Page After Jquery.Get to MVC Controller Action
Restsharp Post Request - Body With X-Www-Form-Urlencoded Values
Save Byte[] into a SQL Server Database from C#
Storing Enums as Strings in Mongodb
Visual Studio Solution Unavailable (Reload Doesn't Work)
Web-Api Post Body Object Always Null
Getting All Attributes from an Iwebelement With Selenium Webdriver