DataTable customization with records - c#

I Have 1 Datatable having 10 rows and ListBox having 8 ListItems contains 6 records from the DataTable and 2 new records.
I want to update the DataTable in such a way that 6 records should be as it is and remove remaining 4 records from DataTable and add 2 newly added entries from ListBox in DataTable.
What I tried is I looped ListBox record from DataTable and created list of matched records.
string impactedTC;
List<int> index = new List<int>();
// This retruns my dataset having 10 records
DataTable dttable = GetImpactedTestCaseDetailsToUpdateStatus().Tables[0];
for (int i = 0; i < ListBox1.Items.Count; i++)
{
int count = 0;
string dTestCase = ListBox1.Items[i].Text;
foreach (DataRow dtRow in dttable.Rows)
{
impactedTC = dtRow["TestCaseName"].ToString();
if (impactedTC == dTestCase)
{
index.Add(count);
}
count++;
}
}

You can do that using Ling:
To keep the 6 rows and remove the remaining 4 from the DataTable:
//Assuming the names are DataTable1 and ListBox1.
var rowsToRemove = from r in DataTable1.Rows.Cast<DataRow>()
where listBox1.Items
.Cast<ListItem>()
.Aggregate(0, (n, li) => li.Text.ToLower() == r.Field<string>("TestCaseName").ToLower() ? n + 1 : n) == 0
select r;
To get the new items from the ListBox:
var newItems = from li in listBox1.Items.Cast<ListItem>()
where DataTable1.Rows
.Cast<DataRow>()
.Aggregate(0, (n, r) => r.Field<string>("TestCaseName").ToLower() == li.Text.ToLower() ? n + 1 : n) == 0
select li;
and finally update the DataTable:
rowsToRemove.ToList().ForEach(r => DataTable1.Rows.Remove(r));
newItems.ToList().ForEach(li => DataTable1.Rows.Add(li.Text)); //or maybe li.Value
Important
You might need to replace any li.Text with li.Value in the preceding code and that depends on how the ListItem objects are created. Please check this for more details.

Related

C# Method will not strip out duplicates. [duplicate]

What is the best way to remove duplicate entries from a Data Table?
Do dtEmp on your current working DataTable:
DataTable distinctTable = dtEmp.DefaultView.ToTable( /*distinct*/ true);
It's nice.
Remove Duplicates
public DataTable RemoveDuplicateRows(DataTable dTable, string colName)
{
Hashtable hTable = new Hashtable();
ArrayList duplicateList = new ArrayList();
//Add list of all the unique item value to hashtable, which stores combination of key, value pair.
//And add duplicate item value in arraylist.
foreach (DataRow drow in dTable.Rows)
{
if (hTable.Contains(drow[colName]))
duplicateList.Add(drow);
else
hTable.Add(drow[colName], string.Empty);
}
//Removing a list of duplicate items from datatable.
foreach (DataRow dRow in duplicateList)
dTable.Rows.Remove(dRow);
//Datatable which contains unique records will be return as output.
return dTable;
}
Here Links below
http://www.dotnetspider.com/resources/4535-Remove-duplicate-records-from-table.aspx
http://www.dotnetspark.com/kb/94-remove-duplicate-rows-value-from-datatable.aspx
For remove duplicates in column
http://dotnetguts.blogspot.com/2007/02/removing-duplicate-records-from.html
A simple way would be:
var newDt= dt.AsEnumerable()
.GroupBy(x => x.Field<int>("ColumnName"))
.Select(y => y.First())
.CopyToDataTable();
This post is regarding fetching only Distincts rows from Data table on basis of multiple Columns.
Public coid removeDuplicatesRows(DataTable dt)
{
DataTable uniqueCols = dt.DefaultView.ToTable(true, "RNORFQNo", "ManufacturerPartNo", "RNORFQId", "ItemId", "RNONo", "Quantity", "NSNNo", "UOMName", "MOQ", "ItemDescription");
}
You need to call this method and you need to assign value to datatable.
In Above code we have RNORFQNo , PartNo,RFQ id,ItemId, RNONo, QUantity, NSNNO, UOMName,MOQ, and Item Description as Column on which we want distinct values.
Heres a easy and fast way using AsEnumerable().Distinct()
private DataTable RemoveDuplicatesRecords(DataTable dt)
{
//Returns just 5 unique rows
var UniqueRows = dt.AsEnumerable().Distinct(DataRowComparer.Default);
DataTable dt2 = UniqueRows.CopyToDataTable();
return dt2;
}
/* To eliminate Duplicate rows */
private void RemoveDuplicates(DataTable dt)
{
if (dt.Rows.Count > 0)
{
for (int i = dt.Rows.Count - 1; i >= 0; i--)
{
if (i == 0)
{
break;
}
for (int j = i - 1; j >= 0; j--)
{
if (Convert.ToInt32(dt.Rows[i]["ID"]) == Convert.ToInt32(dt.Rows[j]["ID"]) && dt.Rows[i]["Name"].ToString() == dt.Rows[j]["Name"].ToString())
{
dt.Rows[i].Delete();
break;
}
}
}
dt.AcceptChanges();
}
}
There is a simple way using Linq GroupBy Method.
var duplicateValues = dt.AsEnumerable()
.GroupBy(row => row[0])
.Where(group => (group.Count() == 1 || group.Count() > 1))
.Select(g => g.Key);
foreach (var d in duplicateValues)
Console.WriteLine(d);
See more at: http://www.dotnetlines.com/Blogs/tabid/85/EntryId/49/Remove-duplicate-rows-from-a-DataTable-using-LINQ.aspx
Completely distinct rows:
public static DataTable Dictinct(this dt) => dt.DefaultView.ToTable(true);
Distinct by particular row(s) (Note that the columns mentioned in "distinctCulumnNames" will be returned in resulting DataTable):
public static DataTable Dictinct(this dt, params string[] distinctColumnNames) =>
dt.DefaultView.ToTable(true, distinctColumnNames);
Distinct by particular column (preserves all columns in given DataTable):
public static void Distinct(this DataTable dataTable, string distinctColumnName)
{
var distinctResult = new DataTable();
distinctResult.Merge(
.GroupBy(row => row.Field<object>(distinctColumnName))
.Select(group => group.First())
.CopyToDataTable()
);
if (distinctResult.DefaultView.Count < dataTable.DefaultView.Count)
{
dataTable.Clear();
dataTable.Merge(distinctResult);
dataTable.AcceptChanges();
}
}
You can use the DefaultView.ToTable method of a DataTable to do the filtering like this (adapt to C#):
Public Sub RemoveDuplicateRows(ByRef rDataTable As DataTable)
Dim pNewDataTable As DataTable
Dim pCurrentRowCopy As DataRow
Dim pColumnList As New List(Of String)
Dim pColumn As DataColumn
'Build column list
For Each pColumn In rDataTable.Columns
pColumnList.Add(pColumn.ColumnName)
Next
'Filter by all columns
pNewDataTable = rDataTable.DefaultView.ToTable(True, pColumnList.ToArray)
rDataTable = rDataTable.Clone
'Import rows into original table structure
For Each pCurrentRowCopy In pNewDataTable.Rows
rDataTable.ImportRow(pCurrentRowCopy)
Next
End Sub
In order to distinct all datatable columns, you can easily retrieve the names of the columns in a string array
public static DataTable RemoveDuplicateRows(this DataTable dataTable)
{
List<string> columnNames = new List<string>();
foreach (DataColumn col in dataTable.Columns)
{
columnNames.Add(col.ColumnName);
}
return dataTable.DefaultView.ToTable(true, columnNames.Select(c => c.ToString()).ToArray());
}
As you can notice, I thought of using it as an extension to DataTable class
I would prefer this as this is faster than DefaultView.ToTable and foreach loop to remove duplicates. Using this, we can have group by on multiple columns as well.
DataTable distinctDT = (from rows in dt.AsEnumerable()
group rows by new { ColA = rows["ColA"], ColB = rows["ColB"]} into grp
select grp.First()).CopyToDataTable();

Editing DataGridView data changes row orders

I have a DataGridView (dgvVolReport) bound to a DataTable. There is a column in the table called "group" (colGroup on the DataGridView). I am trying to create a button that can group together (i.e. assign the same group number to) all selected rows.
I have the logic of assigning the group numbers and editing the other group number correct and the new groups for each row are stored in a List<int> called groupNumbersAll.
I then transfer these number to the DataGridView like so:
for (int r = 0; r < groupNumbersAll.Count; r++)
{
dgvVolReport.Rows[r].Cells["colGroup"].Value = groupNumbersAll[r];
}
// A breakpoint is set on this line (i.e. values below are BEFORE this line has been run
dgvVolReport.Sort(colGroup, ListSortDirection.Ascending);
And somehow that seems to change the row orders or assign the numbers to the wrong rows.
I have debugged just after that loop and the contents of groupNumbersAll is correct:
Note that those two pinned "sixes" correspond to the two selected rows (they were fives before). Now here is what the contents of the colGroup column look like:
You can see that from row 6 they don't match. Why don't they match? WHY?
But more bizarrely, if I comment out the last line (dgvVolReport.Sort(colGroup, ListSortDirection.Ascending);), which has not even run yet since that's where the breakpoint lies, then suddenly they do match!!! Does anyone know what's going on here?
btw I have also tried unbinding and then rebinding the DataSource which I thought worked for a time but now I see that it does not.
The following is the complete code (from a button click) for the group button as requested (Note that the final working code is here):
private void btnGroup_Click(object sender, EventArgs e)
{
//dgvVolReport.CommitEdit(DataGridViewDataErrorContexts.Commit);
List<int> groupNumbersAll = new List<int>();
List<int> groupNumbersNotSelected = new List<int>();
List<int> groupNumbersSelected = new List<int>();
List<int> rowNumbersSelected = new List<int>();
List<int> groupNumbersOfEntirelySelectedGroups = new List<int>();
// Populate groups (All, Selected and NotSelected)
foreach (DataGridViewRow row in dgvVolReport.Rows)
{
groupNumbersAll.Add(Convert.ToInt16(row.Cells["colGroup"].Value));
if (row.Selected)
{
groupNumbersSelected.Add(Convert.ToInt16(row.Cells["colGroup"].Value));
rowNumbersSelected.Add(row.Index);
}
else
{
groupNumbersNotSelected.Add(Convert.ToInt16(row.Cells["colGroup"].Value));
}
}
int smallestSelectedGroupNumber = groupNumbersSelected.Min();
int newGroupNumber = smallestSelectedGroupNumber;
bool newGroupFlag = false;
// If the selected rows do not contain all rows with group number equal to the smallest selected group number,
// then we need to create a new group whose group number is the smallest selected group number plus 1.
// This then implies that we need to add 1 to the group number of every row with a group number larger than the
// lowest selected group number (that is the original lowest selected number before we added 1).
if (groupNumbersNotSelected.Contains(smallestSelectedGroupNumber))
{
newGroupNumber++;
newGroupFlag = true;
}
// Find which groups have been selected entirely, but ignore the smallest number.
// If a group has been entirely selected it means that that group number will no longer exist. Thus we will have to
// subtract 1 from each group number that is larger than a group that has been entirely selected. This process is
// cumulative, so if a number is higher than 2 entirely selected groups (excluding the smallest selected group) then
// we need to subtract 2 from the group number.
foreach (int group in groupNumbersSelected.Distinct())
{
if (!groupNumbersNotSelected.Contains(group) && !(group == smallestSelectedGroupNumber))
{
groupNumbersOfEntirelySelectedGroups.Add(group);
}
}
// Find the new group numbers
for (int r = 0; r < groupNumbersAll.Count; r++)
{
int groupNum = groupNumbersAll[r];
if (rowNumbersSelected.Contains(r))
{
groupNumbersAll[r] = newGroupNumber;
}
else
{
int subtract = groupNumbersOfEntirelySelectedGroups.Where(num => num < groupNum).Count();
if (newGroupFlag && groupNum >= newGroupNumber)
{
groupNum++;
}
groupNumbersAll[r] = groupNum - subtract;
}
}
//// Unbind the data table because of weird ass sorting error: https://stackoverflow.com/questions/30785736/editing-datagridview-data-changes-row-orders/30799185#30799185
//DataTable dt = (DataTable)dgvVolReport.DataSource;
//dgvVolReport.DataSource = null;
////Alter the values on the underlying DataTable
//for (int r = 0; r < groupNumbersAll.Count; r++)
//{
// dt.Rows[r]["Group"] = groupNumbersAll[r];
//}
////Rebind
//dgvVolReport.DataSource = dt;
//((DataView)dgvVolReport.DataSource).Sort = null;
int counter = 0;
foreach (DataGridViewRow row in dgvVolReport.Rows)
{
row.Cells["colGroup"].Value = groupNumbersAll[counter++];
}
dgvVolReport.Sort(colGroup, ListSortDirection.Ascending);
}
}
I think your groupNumbersAll - or how it is used - is to blame. It is hard to be certain because we can't see how it is used and more importantly, prepared for reuse. This however, is incorrect:
for (int r = 0; r < groupNumbersAll.Count; r++)
{
dgvVolReport.Rows[r].Cells["colGroup"].Value = groupNumbersAll[r];
}
If the DGV is databound, you should not be changing values in the DGV. In fact, if you query a cell after a new assignment, you should see that it is unchanged:
Console.WriteLine(dgvGrouper.Rows[1].Cells[GrpColIndex].Value);
dgvGrouper.Rows[1].Cells[GrpColIndex].Value = 99;
Console.WriteLine(dgvGrouper.Rows[1].Cells[GrpColIndex].Value);
Mine prints the same value before as after. I have to think that the Group value doesn't show on the grid or you would see that the value is not changing. Instead you should be changing the DataSource:
for (int n = 0; n < myDT.Rows.Count; n++)
{
myDT.Rows[n][GrpColIndex] = rList[n];
}
My data looks like this:
The Name and Value both represent the original data order.
The problem is that sorting changes the display order, but not the underlying DataTable - the DGV is simply presenting a View of the data (DataTable -> DataView -> DataGridView control). Dumping the Group values for a sorted DGV, List and DataTable demonstrates this:
*** SORTED DGV Rows to List and DT ***
DGV Grp: 1 List Val: 1 DT Val: 1
DGV Grp: 1 List Val: 2 DT Val: 2
DGV Grp: 1 List Val: 2 DT Val: 2
DGV Grp: 1 List Val: 1 DT Val: 1
DGV Grp: 2 List Val: 1 DT Val: 1
DGV Grp: 2 List Val: 1 DT Val: 1
I grouped rows 2 and 3 thru the DataTable. Afterwards the List and DT are in synch, but the DGV is not. The next time you iterate the DGV for the selected rows those row indices have no relation to the List index or DataTable row index.
Since the DGV selected rows is the starting point, you need to convert a DataGridView selected row index to a DataTable row index. If other things can happen to the DGV (rows added, rows deleted, user sort by column etc), I'd rebuild the List every time (I'd do this anyway since it is so utterly detached from the control and the data):
// rebuild the List from the Group value in the DataTable
rList = new List<int>();
for (Int32 n = 0; n < myDT.Rows.Count; n++)
{
rList.Add((int)myDT.Rows[n][GrpColIndex]);
}
// loop thru the selected rows
foreach(DataGridViewRow dgvr in dgvGrouper.SelectedRows)
{
// get at the underlying data item for this row
// which is likely at a different index than the DGV row
DataRowView dr = (DataRowView)dgvr.DataBoundItem;
// use the DataView.Table to get the index of this DataRowView
rList[dr.DataView.Table.Rows.IndexOf(dr.Row)] = newGrpVal;
}
newGrpVal += 1;
dr.DataView.Table.Rows.IndexOf(dr.Row) basically converts the DGV visual selected row index to the actual DataTable row index. As long as the group values don't have intrinsic meaning, you might be able to use something simple like the counter shown. If you need the current value of the selected rows from the table for a more robust group method dr[GrpColIndex] should contain the value you need.
Example:
Baker and Charlie have already been regrouped. The DGV shows them at the bottom, but we saw that they remain in slots 2 and 3 in the DataTable. Now, after selecting Delta and Echo, the above code runs. View of the indices before changes are applied:
DGV Grp: 1 List Val: 1 DT Val: 1
DGV Grp: 1 List Val: 2 DT Val: 2
DGV Grp: 1 List Val: 2 DT Val: 2
DGV Grp: 1 List Val: 3 DT Val: 1
DGV Grp: 2 List Val: 3 DT Val: 1
DGV Grp: 2 List Val: 1 DT Val: 1
The planned changes are spot on; items 4 and 5 will be set as group #3 and sort to the bottom. Just copy the list to the data source:
for (int n = 0; n < myDT.Rows.Count; n++)
{
myDT.Rows[n][GrpColIndex] = rList[n];
}
It would be nice if something like a Dictionary or Tuple, perhaps using the hashcode from a row could tie things together better, but I cant work out anything which works better than restarting the list.
I'll try to amend with any salient information as time allows once more information about the list and/or grouping is available.
I guess the value has not yet committed to the underlying data source
To modify the underlying data source directly
for (int r = 0; r < groupNumbersAll.Count; r++)
{
var drv = (DataRowView)dgvVolReport.Rows[r].DataBoundItem;
drv.Row["colGroup"] = groupNumbersAll[r];
}
I would also try editing the DataTable directly. Skip using the groupNumbersAll for now and use an incremental value for testing, instead:
DataTable dt = (DataTable)dgvVolReport.DataSource;
dgvVolReport.DataSource = null;
for (int i = 0; i < dt.Rows.Count; i++) {
dt.Rows[i]["Group"] = i;
}
dgvVolReport.DataSource = dt;
//dgvVolReport.Sort(colGroup, ListSortDirection.Ascending);
If each row and column "Group" in the DataGridView doesn't display an unique integer, the problem is in the DataGridView's properties. You should also check the "Group"-column's properties (value type etc).
Based on Plutonix's answer, this is the final working code:
private void btnGroup_Click(object sender, EventArgs e)
{
//See: https://stackoverflow.com/questions/30785736/editing-datagridview-data-changes-row-orders
List<int> groupNumbersAll = new List<int>();
List<int> groupNumbersNotSelected = new List<int>();
List<int> groupNumbersSelected = new List<int>();
List<int> rowNumbersSelected = new List<int>();
List<int> groupNumbersOfEntirelySelectedGroups = new List<int>();
DataTable dt = (DataTable)dgvVolReport.DataSource;
// Populate groups (All, Selected and NotSelected)
for (int r = 0; r < dt.Rows.Count; r++)
{
int group = Convert.ToInt16(dt.Rows[r]["Group"]);
groupNumbersAll.Add(group);
bool selected = false;
foreach (DataGridViewRow gridrow in dgvVolReport.SelectedRows)
{
DataRowView dr = (DataRowView)gridrow.DataBoundItem;
selected |= dr.DataView.Table.Rows.IndexOf(dr.Row) == r;
}
if (selected)
{
groupNumbersSelected.Add(group);
rowNumbersSelected.Add(r);
}
else
{
groupNumbersNotSelected.Add(group);
}
}
int smallestSelectedGroupNumber = groupNumbersSelected.Min();
int newGroupNumber = smallestSelectedGroupNumber;
bool newGroupFlag = false;
// If the selected rows do not contain all rows with group number equal to the smallest selected group number,
// then we need to create a new group whose group number is the smallest selected group number plus 1.
// This then implies that we need to add 1 to the group number of every row with a group number larger than the
// lowest selected group number (that is the original lowest selected number before we added 1).
if (groupNumbersNotSelected.Contains(smallestSelectedGroupNumber))
{
newGroupNumber++;
newGroupFlag = true;
}
// Find which groups have been selected entirely, but ignore the smallest number.
// If a group has been entirely selected it means that that group number will no longer exist. Thus we will have to
// subtract 1 from each group number that is larger than a group that has been entirely selected. This process is
// cumulative, so if a number is higher than 2 entirely selected groups (excluding the smallest selected group) then
// we need to subtract 2 from the group number.
foreach (int group in groupNumbersSelected.Distinct())
{
if (!groupNumbersNotSelected.Contains(group) && !(group == smallestSelectedGroupNumber))
{
groupNumbersOfEntirelySelectedGroups.Add(group);
}
}
// Find the new group numbers
for (int r = 0; r < groupNumbersAll.Count; r++)
{
int groupNum = groupNumbersAll[r];
if (rowNumbersSelected.Contains(r))
{
groupNumbersAll[r] = newGroupNumber;
}
else
{
int subtract = groupNumbersOfEntirelySelectedGroups.Where(num => num < groupNum).Count();
if (newGroupFlag && groupNum >= newGroupNumber)
{
groupNum++;
}
groupNumbersAll[r] = groupNum - subtract;
}
}
for (int n = 0; n < dt.Rows.Count; n++)
{
dt.Rows[n]["Group"] = groupNumbersAll[n];
}
dgvVolReport.Sort(colGroup, ListSortDirection.Ascending);
}

How to count similar values in csv and import into asp.net (C#) gridview?

I have CSV with something like this (uses pipe delimiter)
a|45
b|45
c|55
d|65
e|45
What I want do is display in gridview, the number of entries, something like
45-3
55-1
65-1
How can i achieve this?
I am doing this right now
// get all lines of csv file
string[] str = File.ReadAllLines(Server.MapPath("Test.csv"));
// create new datatable
DataTable dt = new DataTable();
// get the column header means first line
string[] temp = str[0].Split('|');
// creates columns of gridview as per the header name
foreach (string t in temp)
{
dt.Columns.Add(t, typeof(string));
}
// now retrive the record from second line and add it to datatable
for (int i = 1; i < str.Length; i++)
{
string[] t = str[i].Split('|');
dt.Rows.Add(t);
}
// assign gridview datasource property by datatable
GridView1.DataSource = dt;
// bind the gridview
GridView1.DataBind();
It prints out all the data from the csv right now
var data = File.ReadAllLines(Server.MapPath("Test.csv"))
.Select(s => s.Split('|')[1].Trim())
.GroupBy(s => s)
.Select(s => new
{
Value = s.Key,
Count = s.Count()
})
.ToList();
GridView1.DataSource = data;
GridView1.DataBind();
Will get you:
Value Count
45 3
55 1
65 1
GridView1.DataSource = File.ReadAllLines(Server.MapPath("Test.csv")).GroupBy(line => new { l = line.Split('|')[1] }).Select(a => new { text = a.Key.l + "-" + a.Count() }).ToArray();

Retrieve the count of datarows where a column has a value

I have a DataTable with a column named ContainerTitle. I would like to get the count of the number of rows in the DataTable where the ContainerTitle has a particular value. For example, lets say the DataTable has 16 rows where ContainerTitle = "Widget1" and 10 rows where ContainerTitle = "Widget2". I would like to query to get the count of rows where ContainerTitle = "Widget1". Later, when done processing those rows, I would like to get the count of rows where ContainerTitle = "Widget2". I can't figure out how to get the count.
This is what I have come up with so far where the code is incrementing through the datarows:
for(int i=0;i<dt.Rows.Count;i++)
{
DataRow dr = dt.Rows[i];
szContainerName = dr["ContainerTitle"].ToString();
// here is where I am attempting to get the count
var tst = dt.AsEnumerable().Where(p => p.Field<string>("ContainerTitle") == szContainerName );
.
.
.
if (szContainerName != szPrevContainerName)
{
szPrevContainerName= szContainerName ;
}
}
Count would take the predicate, you can use it like:
var count = dt
.AsEnumerable()
.Count(p => p.Field<string>("ContainerTitle") == szContainerName );
You can also add Count to your where clause like:
var count = dt
.AsEnumerable()
.Where(p => p.Field<string>("ContainerTitle") == szContainerName );
.Count();

How to sum columns in a dataTable?

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 & "])", "")
}

Categories