Am using DataTable in C# and am trying to manipulate, modify one of the column. Consider sample data below
Id City Temperature
-------------------
1 A -12
2 B 23
3 C 12
And after conversion i want the below result where am converting Minus to M and Positive values to P
Id City Temperature
-------------------------
1 A 12M
2 B 23P
3 C 12P
Can i achieve this using LINQ..Am parsing this with around 50k Rows and dont want to compromise on performance.what are the other best ways ?
If the column is string instead of double/int:
foreach(DataRow row in table.Rows)
{
string temp = row.Field<string>("Temperature");
bool negative = temp.StartsWith("-");
temp = negative ? temp.Substring(1) + "M" : temp + "P";
row.SetField("Temperature", temp);
}
If the column type is double - as mentioned now - you have to create a new DataTable. You cannot change the DataType after the Datatable is filled with data.
DataTable newTable = table.Clone();
int ordinal = newTable.Columns.IndexOf("Temperature");;
newTable.Columns.Remove("Temperature"); // remove double-column
DataColumn tempCol = newTable.Columns.Add("Temperature"); // string
tempCol.SetOrdinal(ordinal);
foreach (DataRow row in table.Rows)
{
DataRow newRow = newTable.Rows.Add();
foreach(DataColumn col in newTable.Columns)
{
if (col == tempCol)
{
double temp = row.Field<double>("Temperature");
bool negative = temp < 0;
double abs = Math.Abs(temp);
string newTemp = negative ? abs.ToString() + "M" : abs.ToString() + "P";
newRow.SetField(col, newTemp);
}
else
newRow.SetField(col, row[col.ColumnName]);
}
}
Related
I want To Best and Fast Solution.
Dt_AllPage with 2 column and meny rows . column 0 = ModelRam and Column 1 = Price. string.
[dbo].[TBL_Sku_RAM] with columns : [ID]int,[SKU]string,[ModelRam]string,[Price]string
I want to compare Each rows'column ModelRam Of Dt_AllPage with Each Rows' colmun Sku of TBL_Sku_RAM .
for this, select from tbl_sku_ram and append to Dt_SelectTBlRAM and compare two DataTable with names : Dt_AllPage with Dt_SelectTBlRAM
and if Exist regex one rows of Dt_AllPage in Dt_SelectTBlRAM then, get ID of Dt_SelectTBlRAM and get Price of this rowexist Dt_AllPage and update columns : [ModelRam],[Price] of [dbo].[TBL_Sku_RAM];
example:
in Dt_AllPage
ModelRam Price
-------------- ----------
4GB DDR3 PC3 1,000
8GB DDR3 PC3L Geil 1.35V 5,000
in [dbo].[TBL_Sku_RAM]
ID Sku ModelRam Price
--- ----------------- -------------- ----------
1 8GBDDR3 pc3L-1600 null null
2 1GBDDR3-1066 null null
3 2GBDDR2-800 null null
4 1GBDDR2-667 null null
output:
in [dbo].[TBL_Sku_RAM]
ID Sku ModelRam Price
--- ----------------- -------------- ----------
1 8GBDDR3 pc3L-1600 8GB DDR3 PC3L Geil 1.35V 5,000
2 1GBDDR3-1066 null null
3 2GBDDR2-800 null null
4 1GBDDR2-667 null null
code :
1)
for (int i = 0; i < Dt_AllPage.Rows.Count; i++)
{
Model_name = Dt_AllPage.Rows[i][0].ToString();
DataSet Ds_SelectTBlRAM = DAL.SelectTBlRAM();
DataTable Dt_SelectTBlRAM = Ds_SelectTBlRAM.Tables[0];
for (int RowTBL = 0; RowTBL < Dt_SelectTBlRAM.Rows.Count; RowTBL++)
{
if (Regex.IsMatch(Dt_SelectTBlRAM.Rows[RowTBL][1].ToString(), Model_name))
{
int ModelId = (int)Dt_SelectTBlRAM.Rows[RowTBL][0];
string Price = Dt_AllPage.Rows[i][1].ToString();
DAL.Update_Price_Model(Model_name, Price, ModelId);
}
}
}
2)
for (int i = 0; i < .Rows.Count; i++)
{
Model_name = Dt_AllPage.Rows[i][0].ToString();
DataSet Ds_SelectTBlRAM = DAL.SelectTBlRAM();
DataTable Dt_SelectTBlRAM = Ds_SelectTBlRAM.Tables[0];
DataRow row1 = Dt_SelectTBlRAM.AsEnumerable().FirstOrDefault(r => r.Field<string>("SKU").Contains(Model_name));
foreach (DataRow row2 in Dt_SelectTBlRAM.Rows)
{
if (row1 != null)
{
int Model_ID = (from DataRow DR in Dt_SelectTBlRAM.Rows
where (string)DR["SKU"] == Model_name
select (int)DR["ID"]).FirstOrDefault();
}
}
string Price = Dt_AllPage.Rows[i][1].ToString();
Model_name = Dt_AllPage.Rows[i][0].ToString();
}
for (int i = 0; i < Dt_AllPage.Rows.Count; i++)
{
Model_name = Dt_AllPage.Rows[i][0].ToString();
DataSet Ds_SelectTBlRAM = DAL.SelectTBlRAM();
DataTable Dt_SelectTBlRAM = Ds_SelectTBlRAM.Tables[0];
DataRow row1 = Dt_SelectTBlRAM.AsEnumerable().FirstOrDefault(r => r.Field<string>("SKU").Contains(Model_name));
foreach (DataRow row2 in Dt_SelectTBlRAM.Rows)
{
if (row1 != null)
{
int Model_ID = (from DataRow DR in Dt_SelectTBlRAM.Rows
where (string)DR["SKU"] == Model_name
select (int)DR["ID"]).FirstOrDefault();
}
}
string Price = Dt_AllPage.Rows[i][1].ToString();
Model_name = Dt_AllPage.Rows[i][0].ToString();
}
I have two datatables:
1.dtEmployee:
|agent_id|agent_name|sum|
2.dtReport:
|sale_date|agent_id|sum |
------------------------
For each record in dtReport I need to find agent_id in dtEmployee and add the value of dtReport["sum"] to dtEmployee["sum"]:
foreach (DataRow r in dtReport)
{
DataRow empRow = dtEmployee.find(dtReport["agent_id"]);
empRow["sum"] += r["sum"];
}
Is there a way that would allow me to accomplish this?
Something like this works:
private void AddValue(string agent_id, decimal sum)
{
DataRow[] row= dtEmployee.Select("agent_id= '"+agent_id+"'");
//since only one record with this agent_id, we take first record of array -> row[0]
decimal dSum= Convert.ToDecimal(row[0][column]);
dSum+= sum;
row[0]["sum"] = dSum;
}
and insert this function into loop:
foreach (DataRow r in dtReport)
{
AddValue(r["agent_id"], r["sum"]);
}
This can be achieved in many ways.
Option 1 :
foreach(DataRow row in dtEmployee.Rows)
{
var update = dtReport.AsEnumerable().FirstOrDefault(r => r.Field<string>("agent_id") == row.Field<string>("agent_id"));
if(update !=null)
row.SetField<float>("sum", update.Field<float>("sum"));
}
Option 2
Another option would be creating new table by joining DataTables
var results = from t1 in dtEmployee.AsEnumerable()
join t2 in dtReport.AsEnumerable()
on t1.Field<int>("agent_id") equals t2.Field<int>("agent_id")
select new { t1, t2 };
// Now we can construct new DataTable
DataTable result = new DataTable() ;
result.Columns.Add("agent_id", typeof(System.Int32));
result.Columns.Add("Name", typeof(System.String));
result.Columns.Add("sum", typeof(float));
foreach(var dr in results )
{
DataRow newRow = results.NewRow();
newRow["agent_id"] = dr.t1.Field<int>("agent_id");
newRow["agent_name"] = dr.t1.Field<string>("agent_name");
newRow["sum"] = dr.t2.Field<float>("sum");
// When all columns have been filled in then add the row to the table
results.Rows.Add(newRow);
}
Working sample
Hope this helps !
You could try something like this. Given that your agent_id and sum are integer.
foreach (DataRow r in dtReport.Rows)
{
dtEmployee.Select(string.Format("agent_id = {0}", r["agent_id"])).ToList<DataRow>().ForEach(
v => { v["sum"] = (v.IsNull("sum") ? 0 : v.Field<int>("sum")) + (r.IsNull("sum") ? 0 : r.Field<int>("sum")); });
}
Or equivalent code
foreach (DataRow r in dtReport.Rows)
{
DataRow[] empRow = dtEmployee.Select("agent_id = " + r["agent_id"]);
for (int i = 0; i < empRow.Length; i++)
{
empRow[i]["sum"] = (empRow[i].IsNull("sum") ? 0 : (int)empRow[i]["sum"]) + (r.IsNull("sum") ? 0 : (int)r["sum"]);
}
}
I have code like this:
DataTable dt = new DataTable();
// (...) getting data, displaying on DataGridView - all works fine
int columns = dt.Columns.Count; // getting column count
foreach (DataRow row in dt.Rows)
{
for (int c = 0; c < columns; c++) // c is column index
{
// all old values are positive for debugging
double oldVal = Convert.ToDouble(row.ItemArray[c]);
// new values should become negative
double newVal = oldVal * -1;
row.ItemArray[c] = newVal; // im trying to update value like this
// THIS SHOWS POSITIVE NUMBERS (NOT UPDATED)
this.Text = row.ItemArray[c].ToString(); // this is simple debug
}
}
This is a little more complicated, i simplified code.
Why my values are not updated?
Added later:
One more important thing. This data comes from database view, not table. Of course I want to change that data in my DataTable object, not in database.
In the end do this
dt.AcceptChanges();
This Commits all the changes made to this table since the last time AcceptChanges() was called.
DataTable dt = new DataTable();
// (...) getting data, displaying on DataGridView - all works fine
int columns = dt.Columns.Count; // getting column count
foreach (DataRow row in dt.Rows)
{
foreach (DataColumn c in dt.Columns)
{
// all old values are positive for debugging
double oldVal = Convert.ToDouble(row[c]);
// new values should become negative
double newVal = oldVal * -1;
row[c] = newVal; // im trying to update value like this
// THIS SHOWS POSITIVE NUMBERS (NOT UPDATED)
this.Text = row[c].ToString(); // this is simple debug
}
}
dt.AcceptChanges();
EDIT (Added explaination):
Changes to ItemArray elements are not tracked, so no changes are reflected in the datatable values
However you can use ItemArray to change all the row at once, like this:
dt.Rows[0].ItemArray = new object[] {"new value"};
In this case the changes are tracked, and are reflected in datatable.
Update your foreach loop as
foreach (DataRow row in dt.Rows)
{
for (int c = 0; c < columns; c++) // c is column index
{
double oldVal = Convert.ToDouble(row[c]);
double newVal = -oldVal;
row[c] = newVal;
this.Text = row[c].ToString();
}
}
or you can use foreachinstead of for loop as:
foreach (DataRow row in dt.Rows)
{
foreach (DataColumn c in dt.Columns)
{
double oldVal = Convert.ToDouble(row[c]);
double newVal = -oldVal;
row[c] = newVal;
this.Text = row[c].ToString();
}
}
I have 2 datatable let say dtData1 and dtData2. I have records in both the datatable I want to compare both the data table and want to create a new datatable let say dtData3 with uniqe records.
suppose: dtData1 has 10 records, and dtData2 has 50 records, but what ever records are there in dtData2 in that 7 records are same as dtData1. So here I want unique records in dtData3, means I want only 43 records in dtData3.
we don't know in datatable where we have the duplicate, and its possible that we will not have duplicates or its also possible that we will have all duplicate records.
So in dtData3 I need unique records
Some one please help me.
var dtData3 = dtData2.AsEnumerable().Except(dtData1.AsEnumerable(), DataRowComparer.Default);
Use this.. Probably it will help you.
Suppose you have two data table
DataTable dt1 = new DataTable();
dt1.Columns.Add("Name");
dt1.Columns.Add("ADD");
DataRow drow;
for (int i = 0; i < 10; i++)
{
drow = dt1.NewRow();
drow[0] = "NameA" + 1;
drow[1] = "Add" + 1;
dt1.Rows.Add();
}
DataTable dt2 = new DataTable();
dt2.Columns.Add("Name");
dt2.Columns.Add("ADD");
DataRow drow1;
for (int i = 0; i < 11; i++)
{
drow1 = dt2.NewRow();
drow1[0] = "Name" + 1;
drow1[1] = "Add" + 1;
dt2.Rows.Add();
}
Now To solve your problem Call :-
DataTable d3 = CompareTwoDataTable(dt1, dt2);
The method is something like this;--
public static DataTable CompareTwoDataTable(DataTable dt1, DataTable dt2)
{
dt1.Merge(dt2);
DataTable d3 = dt2.GetChanges();
return d3;
}
Then where the need to compare dtData1 and dtData2? Instead you can copy the contents from dtData2 to dtData3 starting from index7.
First Create Array variables to save unique coloumn values for datatable3. Use Foreach loop with second gridview rows. If any match then dnt save it in a array value, if dnt match then save it in arrays. and display it by attaching with third gridview.......
e.g
string[] name = new string[4];
int i=0,j=0;
foreach(GridViewRows gv in GridView1.rows)
{
if(gv.Cells[0].Text == GridView2.Rows[i].Cells[0].Text)' //if match
{
// dnt save
}
else' //if dnt match save in array for further use
{
name[j] = gv.Cells[0].Text;
j= j++;
}
i=i++;
}
After Saving unique values in Array "name"...Bind it in Third Gridview
During DataBound of third Gridview add this method...
Private void GridView3_RowDataBound(object sender,EventArgs e)
{
if(e.Row.RowState == DataControlState.DataRow)
{
foreach(string nm in name)
{
e.Rows.Cells.Add(name);
}
}
}
public DataTable CompareTwoDataTable(DataTable dtOriginalTable, DataTable dtNewTable, ArrayList columnNames)
{
DataTable filterTable = new DataTable();
filterTable = dtNewTable.Copy();
string filterCriterial;
if (columnNames.Count > 0)
{
for (int iNewTableRowCount = 0; iNewTableRowCount < dtNewTable.Rows.Count; iNewTableRowCount++)
{
filterCriterial = string.Empty;
foreach (string colName in columnNames.ToArray())
{
filterCriterial += colName.ToString() + "='" + dtNewTable.Rows[iNewTableRowCount][colName].ToString() + "' AND ";
}
filterCriterial = filterCriterial.TrimEnd((" AND ").ToCharArray());
DataRow[] dr = dtOriginalTable.Select(filterCriterial);
if (dr.Length > 0)
{
filterTable.Rows[filterTable.Rows.IndexOf(filterTable.Select(filterCriterial)[0])].Delete();
}
}
}
return filterTable;
}
How can I get a sum for all the columns in a datatable? Say I had the following table. How can I calculate the "total" row? It should be easy to add total row to a datatable.
Columns hits uniques sigups, etc...
Rows
1 12 1 23
2 1 0 5
3 6 2 9
total 19 3 37
Update
I ended up with this. It was the only thing I could get to work.
For Each col As DataColumn In TotalsTable.Columns
If col.DataType.Name = "DateTime" Then
count = count + 1
Continue For
End If
Dim colTotal As Double = 0
Dim value As Double
For Each row As DataRow In TotalsTable.Rows
If Double.TryParse(row(col), value) Then
colTotal += Double.Parse(row(col))
End If
Next
totalRow(count) = colTotal
count = count + 1
Next
There is also a way to do this without loops using the DataTable.Compute Method. The following example comes from that page. You can see that the code used is pretty simple.:
private void ComputeBySalesSalesID(DataSet dataSet)
{
// Presumes a DataTable named "Orders" that has a column named "Total."
DataTable table;
table = dataSet.Tables["Orders"];
// Declare an object variable.
object sumObject;
sumObject = table.Compute("Sum(Total)", "EmpID = 5");
}
I must add that if you do not need to filter the results, you can always pass an empty string:
sumObject = table.Compute("Sum(Total)", "")
Try this:
DataTable dt = new DataTable();
int sum = 0;
foreach (DataRow dr in dt.Rows)
{
foreach (DataColumn dc in dt.Columns)
{
sum += (int)dr[dc];
}
}
I doubt that this is what you want but your question is a little bit vague
Dim totalCount As Int32 = DataTable1.Columns.Count * DataTable1.Rows.Count
If all your columns are numeric-columns you might want this:
You could use DataTable.Compute to Sum all values in the column.
Dim totalCount As Double
For Each col As DataColumn In DataTable1.Columns
totalCount += Double.Parse(DataTable1.Compute(String.Format("SUM({0})", col.ColumnName), Nothing).ToString)
Next
After you've edited your question and added more informations, this should work:
Dim totalRow = DataTable1.NewRow
For Each col As DataColumn In DataTable1.Columns
totalRow(col.ColumnName) = Double.Parse(DataTable1.Compute("SUM(" & col.ColumnName & ")", Nothing).ToString)
Next
DataTable1.Rows.Add(totalRow)
You can loop through the DataColumn and DataRow collections in your DataTable:
// Sum rows.
foreach (DataRow row in dt.Rows) {
int rowTotal = 0;
foreach (DataColumn col in row.Table.Columns) {
Console.WriteLine(row[col]);
rowTotal += Int32.Parse(row[col].ToString());
}
Console.WriteLine("row total: {0}", rowTotal);
}
// Sum columns.
foreach (DataColumn col in dt.Columns) {
int colTotal = 0;
foreach (DataRow row in col.Table.Rows) {
Console.WriteLine(row[col]);
colTotal += Int32.Parse(row[col].ToString());
}
Console.WriteLine("column total: {0}", colTotal);
}
Beware: The code above does not do any sort of checking before casting an object to an int.
EDIT: add a DataRow displaying the column sums
Try this to create a new row to display your column sums:
DataRow totalsRow = dt.NewRow();
foreach (DataColumn col in dt.Columns) {
int colTotal = 0;
foreach (DataRow row in col.Table.Rows) {
colTotal += Int32.Parse(row[col].ToString());
}
totalsRow[col.ColumnName] = colTotal;
}
dt.Rows.Add(totalsRow);
This approach is fine if the data type of any of your DataTable's DataRows are non-numeric or if you want to inspect the value of each cell as you sum. Otherwise I believe #Tim's response using DataTable.Compute is a better.
It's a pity to use .NET and not use collections and lambda to save your time and code lines
This is an example of how this works:
Transform yourDataTable to Enumerable, filter it if you want , according a "FILTER_ROWS_FIELD" column, and if you want, group your data by a "A_GROUP_BY_FIELD".
Then get the count, the sum, or whatever you wish.
If you want a count and a sum without grouby don't group the data
var groupedData = from b in yourDataTable.AsEnumerable().Where(r=>r.Field<int>("FILTER_ROWS_FIELD").Equals(9999))
group b by b.Field<string>("A_GROUP_BY_FIELD") into g
select new
{
tag = g.Key,
count = g.Count(),
sum = g.Sum(c => c.Field<double>("rvMoney"))
};
for (int i=0;i<=dtB.Columns.Count-1;i++)
{
array(0, i) = dtB.Compute("SUM([" & dtB.Columns(i).ColumnName & "])", "")
}