I have a datatable like this:
date
Type
Agency
TotalCount
ABC_Count
DEF_Count
GHI_Count
JAN-2022
X
B2X
5
5
2
3
JAN-2022
X
C4A
7
5
7
2
FEB-2022
X
B2X
3
2
3
1
FEB-2022
X
C4A
9
1
9
4
MAR-2022
X
B2X
8
3
1
8
MAR-2022
X
C4A
7
1
1
7
JAN-2022
Y
D5Y
6
6
4
3
JAN-2022
Y
E7T
7
3
7
2
FEB-2022
Y
D5Y
4
2
4
1
FEB-2022
Y
E7T
9
2
9
4
MAR-2022
Y
D5Y
8
3
1
8
MAR-2022
Y
E7T
8
1
1
8
Code:
public class GroupModel {
public string LetterGroupName { get; set; }
public List<LetterGroupData> LetterGroupData { get; set; }
}
public class LetterGroupData {
public string Date { get; set; }
public double TypeX_Ave { get; set; }
public double TypeY_Ave { get; set; }
public int Total { get; set; }
}
My desired output would be a list of GroupModel List<GroupModel> and it should be something like this:
"GroupModel" :
[
{
"LetterGroupName" : "ABC",
"LetterGroupData" : [
{
"Date": "JAN-2022",
"TypeX_Ave": 40.0, //Sum ABC_Count for Type X / (Sum of TotalCount for JAN-2022 Type X + Y)
"TypeY_Ave": 36.0,//Sum ABC_Count for Type Y / (Sum of TotalCount for JAN-2022 Type X + Y)
"Total": 25 //sum of TotalCount for JAN-2022 Type X + Y
},
{
"Date": "FEB-2022",
"TypeX_Ave": 12.0, //Sum ABC_Count for Type X / (Sum of TotalCount for FEB-2022 Type X + Y)
"TypeY_Ave": 16.0,//Sum ABC_Count for Type Y / (Sum of TotalCount for FEB-2022 Type X + Y)
"Total": 25 //sum of TotalCount for FEB-2022 Type X + Y
},//..and so on for MAR-2022
]
},
{
"LetterGroupName" : "DEF",
"LetterGroupData" : [
{
"Date": "JAN-2022",
"TypeX_Ave": 36.0, //Sum DEF_Count for Type X / (Sum of TotalCount for JAN-2022 Type X + Y)
"TypeY_Ave": 44.0,//Sum DEF_Count for Type Y / (Sum of TotalCount for JAN-2022 Type X + Y)
"Total": 25 //sum of TotalCount for JAN-2022 Type X + Y
},
{
"Date": "FEB-2022",
"TypeX_Ave": 48.0, //Sum DEF_Count for Type X / (Sum of TotalCount for FEB-2022 Type X + Y)
"TypeY_Ave": 52.0,//Sum DEF_Count for Type Y / (Sum of TotalCount for FEB-2022 Type X + Y)
"Total": 25 //sum of TotalCount for FEB-2022 Type X + Y
},//..and so on for MAR-2022
]
},//...and so on for LetterGroupName GHI
]
How do I achieve this result using only a single LINQ query?
Implementation:
private static IReadOnlyCollection<GroupModel> GetGroups(IReadOnlyCollection<Dictionary<string, object>> input) =>
(
from groupName in new[] { "ABC", "DEF", "GHI" }
select
new GroupModel
{
LetterGroupName = groupName,
LetterGroupData = (
from item in input
group item by (string)item["date"] into itemGroup
let total = itemGroup.Sum(item => (int)item["TotalCount"])
select new LetterGroupData
{
Date = itemGroup.Key,
TypeX_Ave = (double)itemGroup
.Where(item => (string)item["Type"] == "X")
.Sum(item => (int)item[groupName + "_Count"])
/ total * 100,
TypeY_Ave = (double)itemGroup
.Where(item => (string)item["Type"] == "Y")
.Sum(item => (int)item[groupName + "_Count"])
/ total * 100,
Total = total,
}).ToList()
}
).ToList();
Usage:
var input =
new Dictionary<string, object>[]
{
new()
{
["date"] = "JAN-2022",
["Type"] = "X",
["Agency"] = "B2X",
["TotalCount"] = 5,
["ABC_Count"] = 5,
["DEF_Count"] = 2,
["GHI_Count"] = 3,
},
new()
{
["date"] = "JAN-2022",
["Type"] = "X",
["Agency"] = "C4A",
["TotalCount"] = 7,
["ABC_Count"] = 5,
["DEF_Count"] = 7,
["GHI_Count"] = 2,
},
new()
{
["date"] = "JAN-2022",
["Type"] = "Y",
["Agency"] = "B2X",
["TotalCount"] = 6,
["ABC_Count"] = 6,
["DEF_Count"] = 4,
["GHI_Count"] = 3,
},
new()
{
["date"] = "JAN-2022",
["Type"] = "Y",
["Agency"] = "C4A",
["TotalCount"] = 7,
["ABC_Count"] = 3,
["DEF_Count"] = 7,
["GHI_Count"] = 2,
},
// ...
};
var groups = GetGroups(input);
// groups.Dump();
.NET Fiddle
I think this is what you really want getting data from a datatable :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
DataTable dt = new DataTable();
dt.Columns.Add("date", typeof(string));
dt.Columns.Add("Type", typeof(string));
dt.Columns.Add("Agency", typeof(string));
dt.Columns.Add("TotalCount", typeof(int));
dt.Columns.Add("ABC_Count", typeof(int));
dt.Columns.Add("DEF_Count", typeof(int));
dt.Columns.Add("GHI_Count", typeof(int));
dt.Rows.Add(new object[] { "JAN - 2022", "X", "B2X", 5, 5, 2, 3 });
dt.Rows.Add(new object[] { "JAN - 2022", "X", "C4A", 7, 5, 7, 2 });
dt.Rows.Add(new object[] { "FEB - 2022", "X", "B2X", 3, 2, 3, 1 });
dt.Rows.Add(new object[] { "FEB - 2022", "X", "C4A", 9, 1, 9, 4 });
dt.Rows.Add(new object[] { "MAR - 2022", "X", "B2X", 8, 3, 1, 8 });
dt.Rows.Add(new object[] { "MAR - 2022", "X", "C4A", 7, 1, 1, 7 });
dt.Rows.Add(new object[] { "JAN - 2022", "Y", "D5Y", 6, 6, 4, 3 });
dt.Rows.Add(new object[] { "JAN - 2022", "Y", "E7T", 7, 3, 7, 2 });
dt.Rows.Add(new object[] { "FEB - 2022", "Y", "D5Y", 4, 2, 4, 1 });
dt.Rows.Add(new object[] { "FEB - 2022", "Y", "E7T", 9, 2, 9, 4 });
dt.Rows.Add(new object[] { "MAR - 2022", "Y", "D5Y", 8, 3, 1, 8 });
dt.Rows.Add(new object[] { "MAR - 2022", "Y", "E7T", 8, 1, 1, 8 });
List<GroupModel> groups = dt.AsEnumerable().GroupBy(x => x.Field<string>("Agency"))
.Select(x => new GroupModel() {
LetterGroupName = x.Key,
LetterGroupData = x.Select(y => new LetterGroupData() {
Date = y.Field<string>("date"),
TypeX_Ave = x.Where(z => z.Field<string>("Type") == "X").Select(a => a.Field<int>("ABC_Count")).Sum(),
TypeY_Ave = x.Where(z => z.Field<string>("Type") == "Y").Select(a => a.Field<int>("ABC_Count")).Sum(),
Total = x.Sum(a => a.Field<int>("ABC_Count"))
}).ToList(),
}).ToList();
}
}
public class GroupModel
{
public string LetterGroupName { get; set; }
public List<LetterGroupData> LetterGroupData { get; set; }
}
public class LetterGroupData
{
public string Date { get; set; }
public double TypeX_Ave { get; set; }
public double TypeY_Ave { get; set; }
public int Total { get; set; }
}
}
If you really mean that you want totals by date you have to go back to the datatable like this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
DataTable dt = new DataTable();
dt.Columns.Add("date", typeof(string));
dt.Columns.Add("Type", typeof(string));
dt.Columns.Add("Agency", typeof(string));
dt.Columns.Add("TotalCount", typeof(int));
dt.Columns.Add("ABC_Count", typeof(int));
dt.Columns.Add("DEF_Count", typeof(int));
dt.Columns.Add("GHI_Count", typeof(int));
dt.Rows.Add(new object[] { "JAN - 2022", "X", "B2X", 5, 5, 2, 3 });
dt.Rows.Add(new object[] { "JAN - 2022", "X", "C4A", 7, 5, 7, 2 });
dt.Rows.Add(new object[] { "FEB - 2022", "X", "B2X", 3, 2, 3, 1 });
dt.Rows.Add(new object[] { "FEB - 2022", "X", "C4A", 9, 1, 9, 4 });
dt.Rows.Add(new object[] { "MAR - 2022", "X", "B2X", 8, 3, 1, 8 });
dt.Rows.Add(new object[] { "MAR - 2022", "X", "C4A", 7, 1, 1, 7 });
dt.Rows.Add(new object[] { "JAN - 2022", "Y", "D5Y", 6, 6, 4, 3 });
dt.Rows.Add(new object[] { "JAN - 2022", "Y", "E7T", 7, 3, 7, 2 });
dt.Rows.Add(new object[] { "FEB - 2022", "Y", "D5Y", 4, 2, 4, 1 });
dt.Rows.Add(new object[] { "FEB - 2022", "Y", "E7T", 9, 2, 9, 4 });
dt.Rows.Add(new object[] { "MAR - 2022", "Y", "D5Y", 8, 3, 1, 8 });
dt.Rows.Add(new object[] { "MAR - 2022", "Y", "E7T", 8, 1, 1, 8 });
List<GroupModel> groups = dt.AsEnumerable().GroupBy(x => x.Field<string>("Agency"))
.Select(x => new GroupModel() {
LetterGroupName = x.Key,
LetterGroupData = x.Select(y => new LetterGroupData() {
Date = y.Field<string>("date"),
TypeX_Ave = dt.AsEnumerable().Where(z => z.Field<string>("Type") == "X" && z.Field<string>("date") == y.Field<string>("date")).Select(a => a.Field<int>("ABC_Count")).Sum(),
TypeY_Ave = dt.AsEnumerable().Where(z => z.Field<string>("Type") == "Y" && z.Field<string>("date") == y.Field<string>("date")).Select(a => a.Field<int>("ABC_Count")).Sum(),
Total = dt.AsEnumerable().Where(z => (z.Field<string>("Type") == "X" || z.Field<string>("Type") == "Y") && z.Field<string>("date") == y.Field<string>("date")).Select(a => a.Field<int>("ABC_Count")).Sum(),
}).ToList(),
}).ToList();
}
}
public class GroupModel
{
public string LetterGroupName { get; set; }
public List<LetterGroupData> LetterGroupData { get; set; }
}
public class LetterGroupData
{
public string Date { get; set; }
public double TypeX_Ave { get; set; }
public double TypeY_Ave { get; set; }
public int Total { get; set; }
}
}
I have a table as follows
I have a query that runs each day to find anything that's 5 days old or greater and has a status of "In Progress" and set the status to "Declined".
What I need to be able to do is also set the status to "Declined" for anything with a Linked_ID (child) where the ID (Parent) has been changed.
So in the table I already set ID 1 to "Declined" but I also need to set ID's 2,3,4,8 and 10 to "Declined"
Below is what I have so far, any support would be amazing and really helpful
var Process = from a in db.Table1
where a.Status == "In Progress" && a.Date_Created = DateTime.Now.AddDays(-5)
select a;
foreach (Table1 a in Process)
{
a.Status = "Declined";
}
Try following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Declined declined = new Declined();
declined.Query(DateTime.Now.AddDays(1));
}
}
public class Declined
{
DataTable dt;
public Declined()
{
dt = new DataTable();
dt.Columns.Add("ID", typeof(int));
dt.Columns.Add("Status", typeof(string));
dt.Columns.Add("Date Created", typeof(DateTime));
dt.Columns.Add("Link_ID", typeof(int));
dt.Rows.Add(new object[] { 1, "In Progress", new DateTime(2020, 9, 25) });
dt.Rows.Add(new object[] { 2, "Completed", new DateTime(2020, 9, 28),1 });
dt.Rows.Add(new object[] { 3, "In Progress", new DateTime(2020, 9, 28),1 });
dt.Rows.Add(new object[] { 4, "In Progress", new DateTime(2020, 9, 28),1 });
dt.Rows.Add(new object[] { 5, "In Progress", new DateTime(2020, 9, 28),2 });
dt.Rows.Add(new object[] { 6, "In Progress", new DateTime(2020, 9, 28),3 });
dt.Rows.Add(new object[] { 7, "In Progress", new DateTime(2020, 9, 28) });
dt.Rows.Add(new object[] { 8, "In Progress", new DateTime(2020, 9, 28),1 });
dt.Rows.Add(new object[] { 9, "In Progress", new DateTime(2020, 9, 28) });
dt.Rows.Add(new object[] { 10, "In Progress", new DateTime(2020, 9, 28),1 });
}
public void Query(DateTime date)
{
List<DataRow> rows = dt.AsEnumerable().Where(x => (x.Field<string>("Status") == "In Progress") && (date.Date.Subtract(x.Field<DateTime>("Date Created")).Days > 5)).ToList();
foreach(DataRow row in rows)
{
if (rows.Count > 0) ChangeChildren_Recursive(row, row.Field<DateTime>("Date Created"));
}
}
public void ChangeChildren_Recursive(DataRow row, DateTime date)
{
int id = row.Field<int>("ID");
DateTime rowDate = row.Field<DateTime>("Date Created").Date;
string status = row.Field<string>("Status");
if((status == "In Progress") && (date != rowDate)) row["Status"] = "Declined";
List<DataRow> children = dt.AsEnumerable().Where(x => (x.Field<int?>("Link_ID") == id) && (x.Field<int?>("Link_ID") != null)).ToList();
foreach (DataRow childRow in children)
{
ChangeChildren_Recursive(childRow, date);
}
}
}
}
I have a data table and I need to merge the cells with the same values in the columns IPC and Second Best Issuer and sum the values in the columns Dirty value PC and Par Value LC. All the values are type string.
For example:
I'm a beginner with query and I'm looking for simple way to do this in C# with LINQ.
Thank You
Try following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication11
{
class Program
{
static void Main(string[] args)
{
DataTable dt = new DataTable();
dt.Columns.Add("IPC", typeof(int));
dt.Columns.Add("Dirty", typeof(int));
dt.Columns.Add("Second", typeof(string));
dt.Columns.Add("Par", typeof(int));
dt.Rows.Add(new object[] { 1, 5, "BB", 55 });
dt.Rows.Add(new object[] { 1, 4, "B", 30 });
dt.Rows.Add(new object[] { 2, 15, "AAA", 20 });
dt.Rows.Add(new object[] { 1, 10, "BB", 80 });
dt.Rows.Add(new object[] { 2, 20, "AA", 90 });
dt.Rows.Add(new object[] { 2, 30, "AAA", 50 });
dt.Rows.Add(new object[] { 1, 5, "B", 60 });
dt.Rows.Add(new object[] { 2, 15, "AA", 70 });
var groups = dt.AsEnumerable().GroupBy(x => new {ipc = x.Field<int>("IPC"), second = x.Field<string>("Second")}).ToList();
DataTable dtsum = dt.Clone();
foreach(var group in groups)
{
dtsum.Rows.Add(new object[] {group.Key.ipc, group.Sum(y => y.Field<int>("Dirty")), group.Key.second, group.Sum(y => y.Field<int>("Par"))});
}
}
}
}
I need to compare two datatables which are having same schema and move the differences into another datatable. Below is my code which is not working fine:
DataTable dt1 = new DataTable("TableChanged");
dt1.Columns.Add("StateID",typeof(int));
dt1.Columns.Add("StateInitial");
dt1.Columns.Add("IsActive");
dt1.Rows.Add(new object[] { 10, "GA", 1 });
dt1.Rows.Add(new object[] { 11, "HI", 0 });
dt1.Rows.Add(new object[] { 12, "ID", 1 });
dt1.Rows.Add(new object[] { 13, "IL", 1 });
dt1.Rows.Add(new object[] { 14, "IN", 0 });
dt1.Rows.Add(new object[] { 15, "IA", 1 });
dt1.Rows.Add(new object[] { 23, "MN", 0 });
DataTable dt2 = new DataTable("TableOriginal");
dt2.Columns.Add("StateID", typeof(int));
dt2.Columns.Add("StateInitial");
dt2.Columns.Add("IsActive");
dt2.Rows.Add(new object[] { 10, "GA", 1 });
dt2.Rows.Add(new object[] { 11, "HI", 1 });
dt2.Rows.Add(new object[] { 12, "ID", 1 });
dt2.Rows.Add(new object[] { 13, "IL", 0 });
dt2.Rows.Add(new object[] { 14, "IN", 1 });
dt2.Rows.Add(new object[] { 15, "IA", 1 });
dt2.Rows.Add(new object[] { 23, "MN", 1 });
var matched = from table1 in dt1.AsEnumerable()
join table2 in dt2.AsEnumerable() on table1.Field<int>("StateID") equals table2.Field<int>("StateID")
//where table1.Field<object>("IsActive") == "0"
where table1.Field<string>("StateInitial") == table2.Field<string>("StateInitial") || table1.Field<object>("IsActive") == table2.Field<object>("IsActive")
select table1;
var missing = from table1 in dt1.AsEnumerable()
where !matched.Contains(table1)
select table1;
After comparison, I want result like:
StateID|StateInitial|IsActive
11 "HI" 0
13 "IL" 1
14 "IN" 0
23 "MN" 0
You can use DataRowComparer.Default, which compares every field of a DataRow, for the LINQ methods Intersect and Except. The latter gives you the missing rows, your desired result:
DataRowComparer<DataRow> fieldComparer = DataRowComparer.Default;
IEnumerable<DataRow> matched = dt1.AsEnumerable().Intersect(dt2.AsEnumerable(), fieldComparer);
IEnumerable<DataRow> missing = dt1.AsEnumerable().Except(dt2.AsEnumerable(), fieldComparer);
If you want to add the missing rows into a third table, you could use:
DataTable result = missing.CopyToDataTable();
But i suggest to use a different way because that throws an exception if there were no missing rows:
DataTable result = dt1.Clone(); // empty, same schema
foreach(DataRow row in missing)
result.ImportRow(row);