I have a datatable of below columns
Price1 Price2 Price3 Price4 ColSum
------ ------ ------ ------ ------
2.5 4.7 8 99
10 39 88.3 90
99 21 33 3.2
Now, how do I calculate sum of each row using LINQ?
I want to achieve
ColSum = sum(Price1+Price2+Price3+Price4)
for each columns by linq.
You don't need Linq at all; simply use the Expression property:
Gets or sets the expression used to filter rows, calculate the values in a column, or create an aggregate column.
Example:
var dt = new DataTable();
dt.Columns.Add("Price1", typeof(decimal));
dt.Columns.Add("Price2", typeof(decimal));
dt.Columns.Add("Price3", typeof(decimal));
dt.Columns.Add("Price4", typeof(decimal));
dt.Columns.Add("ColSum", typeof(decimal));
dt.Rows.Add(new object[]{2.5, 4.6, 8, 99});
dt.Rows.Add(new object[]{10, 39, 88.3, 90});
dt.Rows.Add(new object[]{99, 21, 33, 3.2});
dt.Columns["ColSum"].Expression = "Price1+Price2+Price3+Price4";
dt now looks like:
This way, you can keep your DataTable and the ColSum column is automatically updated for you.
You just want the sum of each row in a calculated member?
var result = myTable.AsEnumerable().Select(r =>
new {
Price1 = r.Price1,
Price2 = r.Price2,
Price3 = r.Price3,
Price4 = r.Price4,
ColSum = r.Price1 + r.Price2 + r.Price3 + r.Price4
});
var sums = Prices.Select(i => new { ColSum= i.Price1 + i.Price2 + i.Price3 + i.Price4 });
foreach (var sum in sums)
{
Console.WriteLine(sum.ColSum.ToString());
}
var sum = objectList.Select(i => new
{
Sum = i.Price1 + i.Price2+i.Price3+i.Price4
});
With the data table
var result = from p in dt.AsEnumerable()
select new
{
Sum = p.Field<double>("Price1") + p.Field<double>("Price2") + p.Field<double>("Price3") + p.Field<double>("Price4")
};
Try this
var result = from p in priceList
select new
{
Price1 = p.Price1,
Price2 = p.Price2,
Price3 = p.Price3,
Price4 = p.Price4,
ColSum = p.Price1 + p.Price2 + p.Price3 + p.Price4 + p.Price5
};
You should iterate through columns collection for each row:
int sum;
foreach (DataRow row in dt.Rows)
{
sum = dt.Columns.Cast<DataColumn>().Sum(column => Convert.ToInt32(row[column]));
MessageBox.Show("Sum for current row: " + sum);
}
Related
I have Data Table with the following data
Number Type Order count
1 1 R 1
1 1 R 1
1 1 R 1
1 2 R 1
I am looking to get to this result
Number Type Order count
1 1 R 3
1 2 R 1
How can I group by three columns
var result = dt.AsEnumerable()
.GroupBy(x => {x.Field<string>("Number"))//need to group by Type and order also need to sum te total counts
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
What I m trying to do is relatively simple. I would like to use linq to compute some aggregated function on a group and then put the result back into a datatable of the same format. I did a lot of research and think I should use System.Data.DataSetExtensions and copy to datatable funtion. Here is my random datatable:
DataTable ADataTable = new DataTable("ADataTable");
// Fake table data
ADataTable.Columns.Add("PLANT", typeof(int));
ADataTable.Columns.Add("PDCATYPE_NAME", typeof(int));
ADataTable.Columns.Add("Month", typeof(int));
ADataTable.Columns.Add("Year", typeof(int));
ADataTable.Columns.Add("STATUS_NAME_REPORT", typeof(string));
ADataTable.Columns.Add("SAVINGS_PER_MONTH", typeof(double));
for (int i = 0; i < 15; i++)
{
for (int j = 1; j < 5; j++)
{
DataRow row = ADataTable.NewRow();
row["PLANT"] = j;
row["PDCATYPE_NAME"] = j;
row["Month"] = DateTime.Now.Month;
row["Year"] = DateTime.Now.Year;
row["STATUS_NAME_REPORT"] = "Report";
row["SAVINGS_PER_MONTH"] = j*i;
ADataTable.Rows.Add(row);
}
}
Now I will clone this format and do a simple sum on it via linq:
DataTable newtable = ADataTable.Clone();
// The actual query
IEnumerable<DataRow> query = (from rows in ADataTable.AsEnumerable()
group rows by new
{
PLANT = rows.Field<int>("PLANT"),
PDCATYPE_NAME = rows.Field<int>("PDCATYPE_NAME"),
Month = rows.Field<int>("Month"),
Year = rows.Field<int>("Year"),
STATUS_NAME_REPORT = rows.Field<string>("STATUS_NAME_REPORT")
} into g
select new
{
g.Key.PLANT,
g.Key.PDCATYPE_NAME,
g.Key.Month,
g.Key.Year,
g.Key.STATUS_NAME_REPORT,
sum = g.Sum(savings => savings.Field<double>("SAVINGS_PER_MONTH")),
});
newtable = query.CopyToDataTable<DataRow>();
The LINQ works fine but as soon as I put IEnumarable DataRow in front I get error that I cannot convert anonymys type to datarow. But if I put select new datarow I get an error that fields are unknown...
How do I proceed please?
You have multiple options, First is to use reflection to create a DataTable based on IEnumerable<T> and the other options is to populate your DataTable by enumerating your query like:
var query = ADataTable.AsEnumerable()
.GroupBy(row => new
{
PLANT = row.Field<int>("PLANT"),
PDCATYPE_NAME = row.Field<int>("PDCATYPE_NAME"),
Month = row.Field<int>("Month"),
Year = row.Field<int>("Year"),
STATUS_NAME_REPORT = row.Field<string>("STATUS_NAME_REPORT")
});
foreach (var g in query)
{
newtable.LoadDataRow(new object[]
{
g.Key.PLANT,
g.Key.PDCATYPE_NAME,
g.Key.Month,
g.Key.Year,
g.Key.STATUS_NAME_REPORT,
g.Sum(savings => savings.Field<double>("SAVINGS_PER_MONTH"))
}, LoadOption.OverwriteChanges);
}
The error in your code is because of selecting an anonymous type using select new and then trying to store it in IEnumerable<DataRow>. You can't specify DataRow in select as it is not accessible directly.
You may also see: How to: Implement CopyToDataTable Where the Generic Type T Is Not a DataRow
This also works:
newtable2 = ADataTable.AsEnumerable().GroupBy(a => new
{
PLANT = a.Field<int>("PLANT"),
PDCATYPE_NAME = a.Field<int>("PDCATYPE_NAME"),
Month = a.Field<int>("Month"),
Year = a.Field<int>("Year"),
STATUS_NAME_REPORT = a.Field<string>("STATUS_NAME_REPORT")
}).Select(g =>
{
var row = newtable2.NewRow();
row.ItemArray = new object[]
{
g.Key.PLANT,
g.Key.PDCATYPE_NAME,
g.Key.Month,
g.Key.Year,
g.Key.STATUS_NAME_REPORT,
g.Sum(r => r.Field<double>("SAVINGS_PER_MONTH"))
};
return row;
}).CopyToDataTable();
using System.Data.DataSetExtensions (Which requires a reference)
I have two DataTables and I want to display the rows. if both the datatables having the same value, Then mark X in all columns or else select the column with highest value(Eg:DT1: 10,DT2 :5)
Datatable1
id Name Weight
1 Ship 500
2 Train 600
3 Plane 700
4 Car 800
Datatable2
id Name Weight
1 Ship 500
3 Plane 600
4 Car 200
I want the result to be:
Datatable3
id Name Weight Datatable1 Datatable2
1 Ship 500 X X
2 Train 600 X
3 Plane 700 X X
4 Car 800 X
I have tried the below:-
DataTable Datatable3 = (from a in Datatable1.AsEnumerable()
join b in Datatable2.AsEnumerable()
on a["Name"].ToString() equals b["Name"].ToString()
a["Weight"].ToString() equals b["Weight"].ToString() into g
where g.Count() != 1 select a).CopyToDataTable();
dataGrid1.ItemsSource = Datatable3.DefaultView;
Please help me on this. Thanks in advance
This is what I have:-
DataTable Datatable3 = dt1.AsEnumerable().Union(dt2.AsEnumerable())
.GroupBy(x => x.Field<int>("Id"))
.Select(x =>
{
var topWeightItem = x.OrderByDescending(z => z.Field<int> ("Weight")).First();
return new Items
{
Id = x.Key,
Name = topWeightItem.Field<string>("Name"),
Weight = topWeightItem.Field<int>("Weight"),
DataTable1 = dt1.AsEnumerable().Any(z => z.Field<int>("Id") == x.Key
&& z.Field<int>("Weight") == topWeightItem.Field<int>("Weight")
&& z.Field<string>("Name") == topWeightItem.Field<string>("Name"))
? "X" : String.Empty,
DataTable2 = dt2.AsEnumerable().Any(z => z.Field<int>("Id") == x.Key
&& z.Field<int>("Weight") == topWeightItem.Field<int>("Weight")
&& z.Field<string>("Name") == topWeightItem.Field<string>("Name"))
? "X" : String.Empty
};
}
).PropertiesToDataTable<Items>();
Since It is returning an anonymous type, you can't use CopyToDataTable method, so please check this to understand how I converted it into a datatable.
I am getting this output:-
I have used following type for conversion purpose:-
public class Items
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Weight { get; set; }
public string DataTable1 { get; set; }
public string DataTable2 { get; set; }
}
I have written in two query to achieve what you said..Perhaps you can optimize it further.
//datatable1
DataTable dt1 = new DataTable();
dt1.Columns.Add("Id");
dt1.Columns.Add("Name");
dt1.Columns.Add("Weight");
DataRow dr ;
dr = dt1.NewRow();
dr["Id"] = 1;
dr["Name"] = "Ship";
dr["Weight"] = 500;
dt1.Rows.Add(dr);
dr = dt1.NewRow();
dr["Id"] = 2;
dr["Name"] = "Train";
dr["Weight"] = 600;
dt1.Rows.Add(dr);
dr = dt1.NewRow();
dr["Id"] = 3;
dr["Name"] = "Plane";
dr["Weight"] = 700;
dt1.Rows.Add(dr);
dr = dt1.NewRow();
dr["Id"] = 4;
dr["Name"] = "Car";
dr["Weight"] = 400;
dt1.Rows.Add(dr);
//datatable2
DataTable dt2 = new DataTable();
dt2.Columns.Add("Id");
dt2.Columns.Add("Name");
dt2.Columns.Add("Weight");
DataRow dr2;
dr2 = dt2.NewRow();
dr2["Id"] = 1;
dr2["Name"] = "Ship";
dr2["Weight"] = 500;
dt2.Rows.Add(dr2);
dr2 = dt2.NewRow();
dr2["Id"] = 3;
dr2["Name"] = "Plane";
dr2["Weight"] = 700;
dt2.Rows.Add(dr2);
dr2 = dt2.NewRow();
dr2["Id"] = 4;
dr2["Name"] = "Car";
dr2["Weight"] = 400;
dt2.Rows.Add(dr2);
//iterate through table1
IEnumerable<DataRow> table1 = from r in dt1.AsEnumerable()
select r;
//iterate through table2
IEnumerable<DataRow> table2 = from r in dt2.AsEnumerable()
select r;
Console.WriteLine("Id\tName\tWeight\tDatatable1\tDatatable2");
Console.WriteLine("----------------------------------------------------");
//prints the common records
foreach (DataRow td1 in table1.Distinct())//Matches wholes of the Element Sequence inside IEnumerable
{
table2.Distinct().ToList().ForEach(td2 =>
{
if (td1.Field<string>("Id") == td2.Field<string>("Id"))
{
Console.WriteLine(td1.Field<string>("Id") + "\t" + td1.Field<string>("Name") + "\t" + td1.Field<string>("Weight") + "\t" + "x" + "\t\t" + "x");
}
});
}
//prints the missing records
var query = (from tb1 in dt1.AsEnumerable()
join tb2 in dt2.AsEnumerable()
on tb1.Field<string>("Id") equals tb2.Field<string>("Id") into subset
from sc in subset.DefaultIfEmpty()
where sc == null
select new
{
id = tb1.Field<string>("Id"),
name = tb1.Field<string>("Name"),
wt = tb1.Field<string>("Weight")
}).Distinct();
foreach (var td1 in query)
{
Console.WriteLine(td1.id + "\t" + td1.name + "\t" + td1.wt + "\t" + "x" + "\t\t" + "-");
}
I have a datatable that looks like below
My result Should be A=40% , B=60% .. ie 2/5 and 3/5
Group name can be A, B, C, etc...
How can i calculate the figures based on that datatable values??
You could use LINQ and cast it to a dictionary:
DataTable dt = new DataTable("test1");
dt.Columns.AddRange(new DataColumn[] { new DataColumn("TASKID"), new DataColumn("GROUPID"), new DataColumn("GROUPNAME") });
dt.Rows.Add(new object[] { 12, 2, "A" });
dt.Rows.Add(new object[] { 13, 3, "B" });
dt.Rows.Add(new object[] { 12, 2, "A" });
dt.Rows.Add(new object[] { 14, 3, null });
dt.Rows.Add(new object[] { 15, 3, "B" });
var query = (from DataRow row in dt.Rows
group row by row["GROUPNAME"] into g
select g).ToDictionary(x => (x.Key.ToString() == "" ? "*" : x.Key.ToString()), x => (int)((x.Count() * 100) / dt.Rows.Count));
Iterate through the dictionary to display the values:
foreach(KeyValuePair<string,int> kvp in query)
Console.WriteLine(kvp.Key + " - " + kvp.Value.ToString());
The output:
A - 40
B - 40
* - 20
The percentage is cast as an int. simply change (int)((x.Count() * 100) / dt.Rows.Count) if you need more accurate values.
A simple way, through loop. The following should be similar to the one you require.
//Simulated datatable
DataTable table1 = new DataTable();
table1.Columns.Add(new DataColumn("TaskID", typeof(int)));
table1.Columns.Add(new DataColumn("GroupID", typeof(int)));
table1.Columns.Add(new DataColumn("GroupName", typeof(String)));
//Entered test values
DataRow dr1 = null;
dr1 = table1.NewRow();
dr1["TaskID"] = 12;
dr1["GroupID"] = 2;
dr1["GroupName"] = "A";
table1.Rows.Add(dr1);
dr1 = table1.NewRow();
dr1["TaskID"] = 13;
dr1["GroupID"] = 3;
dr1["GroupName"] = "B";
table1.Rows.Add(dr1);
dr1 = table1.NewRow();
dr1["TaskID"] = 14;
dr1["GroupID"] = 2;
dr1["GroupName"] = "A";
table1.Rows.Add(dr1);
dr1 = table1.NewRow();
dr1["TaskID"] = 15;
dr1["GroupID"] = 3;
dr1["GroupName"] = "B";
table1.Rows.Add(dr1);
dr1 = table1.NewRow();
dr1["TaskID"] = 16;
dr1["GroupID"] = 3;
dr1["GroupName"] = "B";
table1.Rows.Add(dr1);
//solution starts from here
Dictionary<string, int> totalCount = new Dictionary<string, int>();
for (int i = 0; i < table1.Rows.Count; i++)
{
if (totalCount.Keys.Contains(table1.Rows[i]["GroupName"].ToString()))
{
int currVal = totalCount[table1.Rows[i]["GroupName"].ToString()];
totalCount[table1.Rows[i]["GroupName"].ToString()] = currVal + 1;
}
else
{
totalCount[table1.Rows[i]["GroupName"].ToString()] = 1;
}
}
foreach (var item in totalCount)
{
MessageBox.Show(item.Value.ToString());
}
OR
//solution starts from here
var data = table1.AsEnumerable().GroupBy(m => m.Field<string>("GroupName")).Select(grp => new
{
GroupName = grp.Key,
Count = (int)grp.Count()
}).ToList();
Hope this helps
Use Linq
var data=datatable.AsEnumerable().GroupBy(m => m.Field<string>("GROUPNAME")).Select(grp => new
{
GROUPNAME= grp.Key,
Count = (int)grp.Count()
});
I am iterating on a lot of strings and I want to fill my first(and only) 3 Columns with each result and then start again in a new row. like:
A | B | C
------+--------+------
"DOG" | "CAT" | "FISH"
"FDF" | "AAA" | "RRR"
AND SO ON....
Basically after each row is "full" open new row.
HtmlNodeCollection tables = doc.DocumentNode.SelectNodes("//table");
HtmlNodeCollection rows = tables[2].SelectNodes(".//tr");
DataTable dataTable = new DataTable();
dataTable.Columns.Add("A", typeof(string));
dataTable.Columns.Add("B", typeof(string));
dataTable.Columns.Add("C", typeof(string))
try like this
for (int i = 0; i < rows .Count(); i++)
{
DataRow datarowObj= dataTable .NewRow();
datarowObj["A"] = yourValue;
datarowObj["B"] = yourValue;
datarowObj["C"] = yourValue;
dataTable.Rows.Add(datarowObj);
}
You could use Linq's GroupBy to split the long list into groups of 3:
sample-data:
DataTable table = new DataTable();
table.Columns.Add("Col1");
table.Columns.Add("Col2");
table.Columns.Add("Col3");
List<string> longList = Enumerable.Range(1, 99).Select(i => "row " + i).ToList();
group the long list into parts of three:
var groupsWithThree = longList
.Select((s, i) => new { Str = s, Index = i })
.GroupBy(x => x.Index / 3);
add them to the table:
foreach (var group3 in groupsWithThree)
table.Rows.Add(group3.First().Str, group3.ElementAt(1).Str, group3.Last().Str);
Note that it presumes that the list is divisible by three.
Manage with DataRoxw, for instance, after adding an empty DataRow to your DataTable :
DataRow row = table.Rows[0];
foreach (object item in row.ItemArray)
{
?
dataTable.Rows.Add(new object[] { "A1", "B1", "C1" })
// Alternatively
object[] arr = new object[] { "A2", "B2", "C2" };
dataTable.Rows.Add(arr);