I'm making a function which group by 1 value and shows average results against group value. but when i write query in sql it shows average like this value(73.6868877912465). but when i get out average from c# using data table it gives this (4.59396937660475) value. Here is the code which i wrote first
protected DataTable Group(DataTable _dt)
{
DataTable dTable = new DataTable();
dTable.Columns.Add("Region_Name", typeof(string));
dTable.Columns.Add("PercentComplete", typeof(Double));
var query = from row in _dt.AsEnumerable()
group row by row.Field<string>("Region_Name") into grp
let PercentComplete = grp.Select(r => r.Field<Double>("PercentComplete")).Count()
select new
{
Region_Name = grp.Key,
PercentComplete = grp.Sum(r => r.Field<Double>("PercentComplete"))/PercentComplete
};
foreach (var grp in query)
{
dTable.Rows.Add(grp.Region_Name, grp.PercentComplete);
}
return dTable;
}
and then i modified it:
protected DataTable Group(DataTable _dt)
{
DataTable dTable = new DataTable();
dTable.Columns.Add("Region_Name", typeof(string));
dTable.Columns.Add("PercentComplete", typeof(Double));
var query = from row in _dt.AsEnumerable()
group row by row.Field<string>("Region_Name") into grp
select new
{
Region_Name = grp.Key,
PercentComplete = grp.Average(r => r.Field<Double>("PercentComplete"))
};
foreach (var grp in query)
{
dTable.Rows.Add(grp.Region_Name, grp.PercentComplete);
}
return dTable;
}
but both functions are producing same results. Kindly help me out of this
problem.
This image is on web which shows average resuly
enter image description here
This Image is on Database
enter image description here
Related
I want to return a list of extracted data from two tables into a DataGridView with given column names.
public DataTable GetInfo(int id)
{
var stats = new List<string>();
using MyContext db = new MyContext();
var linqResult = (from Round in db.Rounds
join Hands in db.Hands on Round.RoundID equals Hands.RoundID
where Round.UserID == id
select new
{
ID = Round.RoundID,
Status = Round.Status,
DatePlayed = Round.DatePlayed,
Cards = Hands.PlayerCards,
Score = Hands.PlayerScore
});
return (DataTable)linqResult;
}
The code above returns the correct values but the names of the columns are set to default in the DataGridView. I did some google searching and tried ToString() but I am not able to figure out the correct return type as linqResult is defined as a Generic List with anonymous types. What I want is to avoid naming all the columns manually.
Thank you!
Code below will put your data into a DataTable
DataTable dt = new DataTable();
dt.Columns.Add("ID", typeof(string));
dt.Columns.Add("Status", typeof(string));
dt.Columns.Add("DatePlayed", typeof(DateTime));
dt.Columns.Add("Cards", typeof(string));
dt.Columns.Add("Score", typeof(int));
foreach (var result in linqResult)
{
dt.Rows.Add(new object[] { result.ID, result.Status, result.DatePlayed, result.Cards, result.Score });
}
I have two datatable DurationByCurrency(inside a dataset) and Fund which looks like below
I want to delete the rows in Duration By Currency Datatable whose FundCode has value as 2 in Fund Dt by performing a join.
var result = from table1 in raptorDS.Tables[RaptorTable.DurationByCurrency].AsEnumerable()
join table2 in fundDT.AsEnumerable()
on table1.Field<string>("FundCode") equals table2.Field<string>("FundCode") into ps
from row in ps.DefaultIfEmpty()
{
//delete query
}
Please help me on this as I am new to LINQ.
var result = from row1 in raptorDS.Tables[RaptorTable.DurationByCurrency].AsEnumerable()
join row2 in fundDT.AsEnumerable()
on row1.Field<string>("FundCode") equals row2.Field<string>("FundCode")
where row1.Field<string>("value")
equals "2" select row1;
result.ToList().ForEach(row => row.Delete());
sample test code for linqpad:
void Main()
{
//sample data for test
DataSet ds = new DataSet();
ds.Tables.Add(GetTable1());
ds.Tables.Add(GetTable2());
var result = ( from rec1 in ds.Tables[0].AsEnumerable()
join rec2 in ds.Tables[1].AsEnumerable()
on rec1.Field<string>("FC") equals rec2.Field<string>("FC")
where rec2.Field<int>("Value") == 2 select rec1);
result.ToList().ForEach(row => row.Delete());
//now you have only "ABCD" and "AZY" in table 1
//ds.Tables[0].Dump(); linqpad display result
}
DataTable GetTable1()
{
DataTable table = new DataTable();
table.Columns.Add("FC", typeof(string));
table.Rows.Add("ABCD");
table.Rows.Add("XYZ");
table.Rows.Add("AZY");
return table;
}
DataTable GetTable2()
{
DataTable table = new DataTable();
table.Columns.Add("FC", typeof(string));
table.Columns.Add("Value", typeof(int));
table.Rows.Add("ABCD", 1);
table.Rows.Add("XYZ", 2);
table.Rows.Add("AZY",3);
return table;
}
I have data like this..
ID
1234-001
1234-002
1234-003
5678-001
7890-001
7890-002
I am holding this data in a datatable. I am attempting to do some processing on the rows by groups based on the base number i.e. 1234, 5678, 7890
How can I iterate through this datatable and hold in new (temp) datatable
1234-001,1234-002, 1234-003
clear the temp datatable then hold
5678-001
clear the temp datatable then hold
7890-001,7890-002
I am working on an old code base and LINQ is not available. I cant come up with an elegant solution. Maybe something to do with dataviews im not sure?
You say you don't want to use LINQ but would prefer an elegant solution... Unless I am missing something vital in your question, this LINQified code seems to let you do what you want.
var grouped = from d in data
group d by d.Id.Split('-').FirstOrDefault();
foreach(var g in grouped) {
// do something with each group
}
Non-LINQ, non-var answer:
DataTable data = new DataTable();
data.Columns.Add("ID");
data.Columns.Add("Value");
data.Rows.Add("1234-001", "Row 1");
data.Rows.Add("1234-002", "Row 2");
data.Rows.Add("1234-003", "Row 3");
data.Rows.Add("5678-001", "Row 4");
data.Rows.Add("7890-001", "Row 5");
data.Rows.Add("7890-002", "Row 5");
Dictionary<String, List<DataRow>> grouped = new Dictionary<String, List<DataRow>>();
foreach(DataRow r in data.Select()) {
List<DataRow> groupedRows;
String key = r["ID"].ToString().Split('-')[0];
if(!grouped.TryGetValue(key, out groupedRows)) {
groupedRows = new List<DataRow>();
grouped[key] = groupedRows;
}
groupedRows.Add(r);
}
foreach(KeyValuePair<String, List<DataRow>> g in grouped) {
String groupKey = g.Key;
Console.WriteLine(groupKey);
foreach(DataRow r in g.Value) {
Console.WriteLine("\t{0}", r["Value"]);
}
}
I get the following output, so I'm not seeing "it only groups the first 3 and stops":
1234
Row 1
Row 2
Row 3
5678
Row 4
7890
Row 5
Row 5
Here is a non Linq example. Since you say it's sorted you can do it in one loop.
DataTable dt1 = new DataTable();
dt1.Columns.Add("ID", typeof (string));
dt1.Rows.Add("1234-001");
dt1.Rows.Add("1234-002");
dt1.Rows.Add("1234-003");
dt1.Rows.Add("5678-001");
dt1.Rows.Add("7890-001");
dt1.Rows.Add("7890-002");
int i = 0;
while (i < dt1.Rows.Count)
{
DataRow row = dt1.Rows[i];
string key = row.Field<string>("ID").Split('-')[0];
DataView dv = new DataView(dt1);
dv.RowFilter = String.Format("ID LIKE '{0}*'", key.Replace("'", "''"));
DataTable tempdt = dv.ToTable();
i = i + tempdt.Rows.Count;
}
Does this help some?
DataTable dt = new DataTable();
dt.Columns.Add("Data", typeof(string));
dt.Rows.Add("1234-001");
dt.Rows.Add("1234-002");
dt.Rows.Add("1234-003");
dt.Rows.Add("5678-001");
dt.Rows.Add("7890-001");
dt.Rows.Add("7890-002");
var stuff = from dr in dt.Select()
group dr by dr["Data"].ToString().Split('-')[0] into g
select new {First = g.Key, Records = g.ToList()};
stuff.Dump();
var groups = table.AsEnumerable();
List<List<DataRow>> groupList = (from g in table.AsEnumerable()
group g by g.Field<string>("id").ToString().Split('-').First() into Group1
select Group1.ToList()).ToList();
I have written a program to compare two datatables with unique ids and create another datatable to insert certain columns which have the same id in common. I have demonstrated my requirement below.
These are the tables that needs to be compared:
And i need the output as below
but i receive an empty table as the result. I cannot understand where have i gone wrong. Could you please help me on this. I have provided my coding below.Please not that quantity and input are two datatables
DataTable result = new DataTable();
result.Columns.AddRange(new DataColumn[2] { new DataColumn("id"), new DataColumn("qty") });
foreach (DataRow row1 in input.Rows)
{
foreach (DataRow row2 in quantity.Rows)
{
if (row1["id"].ToString() == row2["id"].ToString())
{
result.ImportRow(row2);
}
else
{
result.ImportRow(row1);
}
}
}
return result;
You need a Left Join of 2 Data tables.
DataTable dtinput = new DataTable();
DataTable dtquantity = new DataTable();
dtinput.Columns.Add("id",typeof(int));
dtinput.Rows.Add("2");
dtinput.Rows.Add("4");
dtinput.Rows.Add("7");
dtquantity.Columns.Add("id", typeof(int));
dtquantity.Columns.Add("qty", typeof(int));
dtquantity.Rows.Add("1", "12");
dtquantity.Rows.Add("2", "13");
dtquantity.Rows.Add("3", "5");
dtquantity.Rows.Add("4", "6");
dtquantity.Rows.Add("7", null);
var results = from table1 in dtinput.AsEnumerable()
join table2 in dtquantity.AsEnumerable()
on (int)table1["id"] equals (int)table2["id"]
into outer
from row in outer.DefaultIfEmpty<DataRow>()
select row;
DataTable dt = results.CopyToDataTable();
This diagram should help you in future:
Try something like this:
var result = input.Rows.Where(x => quantity.Rows.Amy(y => x == y));
I hope this helps!
I have a datatable with 20 columns. But i don't need all the columns for the current processing except 5. So i did the below to remove the columns
List<string> clmnames = new List<string>() { "clm6","clm7"..."clm20" };
foreach (string dcName in clmnames)
{
TestAndRemoveColumn(dcName, ds.Tables["TestTable"]);
}
private void TestAndRemoveColumn(string dcName,DataTable datatable)
{
DataColumnCollection dcCollection = datatable.Columns;
if (dcCollection.Contains(dcName))
{
dcCollection.Remove(dcName);
}
}
Instead of looping through the 15 times is there any other way to achieve using easily ?
try this
List<string> listtoRemove = new List<string> { "CLM6", "CLM7", "CLM20" };
for (int i = dt.Columns.Count - 1; i >= 0; i--)
{
DataColumn dc = dt.Columns[i];
if (listtoRemove.Contains(dc.ColumnName.ToUpper()))
{
dt.Columns.Remove(dc);
}
}
In some scenarios may be preferable to clone DataTable and specify columns to copy.
DataView view = new DataView(table);
DataTable table2 = view.ToTable(false, "clm6", "clm7", ...);
Problem seems to be in your code, you get all the comlumns from the datatable then remove the columns but you have not again assign the columns to that datatable
first you get columns
DataColumnCollection dcCollection = datatable.Columns; // get cols
if (dcCollection.Contains(dcName))
{
dcCollection.Remove(dcName); /// remove columns
// but you have not updated you datatable columns.
here should be something like this
datatable.Columns = dcCollection; /// i don't know this will work or not check it
}
Try this
DataTable dt;
dt.Columns.Remove("columnName");
dt.Columns.RemoveAt(columnIndex);
you can use them as
private void TestAndRemoveColumn(string dcName,DataTable datatable)
{
DataTable dt = datatable;
dt.Columns.Remove("dcName");
}
Alternatively you can select only the required columns(Only 5 in your case) like this.
DataTable dt = new DataTable();
dt.Columns.Add("ID");
dt.Columns.Add("Value");
dt.Rows.Add("1", "One");
dt.Rows.Add("2", "Two");
string[] arr= new string[1];
arr[0] = "Value";//add the required columns to the array
//return only the required columns.
DataTable dt2 = dt.DefaultView.ToTable(false, arr);
You could join the columns you want remove with the available columns:
var keepColNames = new List<String>(){ "clm5" };
var allColumns = tbl.Columns.Cast<DataColumn>();
var allColNames = allColumns.Select(c => c.ColumnName);
var removeColNames = allColNames.Except(keepColNames);
var colsToRemove = from r in removeColNames
join c in allColumns on r equals c.ColumnName
select c;
while (colsToRemove.Any())
tbl.Columns.Remove(colsToRemove.First());
If you know that you only have few remaining columns, you could add the column(s):
var colsToAdd = (from keepCol in keepColNames
join col in tbl.Columns.Cast<DataColumn>()
on keepCol equals col.ColumnName
select col).ToList();
tbl.Columns.Clear();
foreach (var colToAdd in colsToAdd)
tbl.Columns.Add(colToAdd);