Looping through each element in a DataRow - c#

Basically, I have a DataTable as below:
I want to run a method per element per row which has the parameters
AddProductPrice(SKU, Price, PriceBracket)
As an example...:
If we take the first row of data, the method will be run a potential of 16 times, once for each time Total Price X isn't null.
So for the first total price in the first row the call will be:
AddProductPrice(SKU, <Total Price 1 value>, 1)
Then for the second total price in the first row the call will be:
AddProductPrice(SKU, <Total Price 2 value>, 2)
Please note: for the National Selling element the call would be:
AddProductPrice(SKU, <National Selling value>, 16)
Is there a clever way to loop through each element in a DataRow to make the procedure more efficient?

For each row, looping through the columns and then finding the index of "Total Price", "National Selling" and adding product price accordingly.
for (int i = 0; i < dataTable.Rows.Count; i++)
{
DataRow myRow = dataTable.Rows[i];
for (int j = 0; j < dataTable.Columns.Count; j++)
{
if (dataTable.Columns[j].ColumnName.IndexOf("Total Price") > 0)
{
AddProductPrice(SKU, myRow.ItemArray[j], j);
}
else if (dataTable.Columns[j].ColumnName.IndexOf("National Selling") > 0)
{
AddProductPrice(SKU, myRow.ItemArray[j], 16); //
}
}
}

Loop through the DataTable.Columns Collection and parse based on the Column Name.
for(int i=0;i < dt.Columns.Count; i++)
{
if (dt.Columns[i].ColumnName.StartsWith("Total Price"))
{
var curBracket = Convert.ToInt32(dt.Columns[i].ColumnName.SubString(11));
AddProductPrice(SKU, curRow[dt.Columns[i].ColumnName, curBracket);
}
}

You can use the ItemArray (type object[]) property of DataRow and iterate through its elements from column tab.Columns.IndexOf("Trade Price 1") to tab.Columns.IndexOf("Trade Price 16").
Beware though, if the column order changes for some reason, your code could break. The safe way would be to iterate through items via an indexer - row["Trade Price " + i].

Related

How to get the sum of multiple columns of a datatable in c#

I want to get the sum of only three columns for each data row in datable. I have a DT with approx 15 columns and I only want the sum of column 7, column 9 and column 10. And all the columns are of string type.
I tried few methods using LINQ but all failed.
If all columns are strings but actually represent floating point numbers:
double totalSum = dt.AsEnumerable()
.Sum(r=> double.Parse(r[7].ToString()) + double.Parse(r[9].ToString()) + double.Parse(r[10].ToString()));
If some are empty or have invalid numbers you need to use double.TryParse.
Here is the solution, it worked for me even if the column type is of string:
for (int i = 11; i < dt.Rows.Count; i++)
{
for (int j = 14; j <= 18; j += 2)
{
if (j > 17)
j -= 1;
if(!string.IsNullOrEmpty(dt.Rows[i][2].ToString()))
{
newdt.Rows.Add(dt.Rows[i][18], dt.Rows[i][19],
dt.Rows[i][j]);
}
}
}
try
{
var result = 0;
if (newdt.Rows.Count != 0)
{
result = newdt.AsEnumerable().Sum(x => Convert.ToInt32(x["Column7"]));
subdt.Rows.Add(dt.Rows[i][18], dt.Rows[i][19], result)
}
...

ListView addition of the sum of numbers in lines

Please help with the code. How can you add numbers from 3,4,5 columns and transfer it to the "Total" column. At the same time, the "Total" column cannot be permanent, for example, listView1.Items [i] .SubItems [11] .Text - this solution is not appropriate, you need to possibly find the "Total" column itself because it is not permanent It can be like SubItems [ 9] 10.11, etc.
Code to write data to listView1
dataReader = await cmd1.ExecuteReaderAsync();
if (dataReader.FieldCount > 0)
{
for (int i = 0; i < dataReader.FieldCount; i++)
{
if (i == 0)
{
listView1.Columns.Add(dataReader.GetName(0), 0, HorizontalAlignment.Left);
}
else
{
listView1.Columns.Add(dataReader.GetName(i).ToString().Replace("_", " "), 80, HorizontalAlignment.Left);
}
}
ListViewItem lv = new ListViewItem();
//
while (await dataReader.ReadAsync())
{
lv = listView1.Items.Add(dataReader[dataReader.GetName(0)].ToString().Replace('_', ' '));
for (int h = 1; h < dataReader.FieldCount; h++)
{
lv.SubItems.Add(dataReader[dataReader.GetName(h)].ToString());
}
}
}
for (int i = 1; i < listView1.Columns.Count; i++)
listView1.Columns[i].Width = -2;
This code assumes there is a column named "Total" in listView1.
(int itt = 1; itt < listView1.Items.Count; itt++)
{
int Totall =
int.Parse(listView1.Items[itt].SubItems[2].Text) +
int.Parse(listView1.Items[itt].SubItems[3].Text) +
int.Parse(listView1.Items[itt].SubItems[4].Text);
//Сумма чисел добавить во всего
listView1.Items[itt].SubItems["Total"].Text = Totall.ToString();
}
int.Parse converts a string to an integer but keep in mind it will throw an exception if the string is not numerical. If you need error checking for that consider using int.TryParse.
Also note that SubItems are 0 indexed. Meaning 0 corresponds to the first visual column, 1 corresponds to the second.

Create 2D array from datatable

I am trying to create a 2D array from a DataTable, however Instead of getting the end result defined below. One row is not added, if that row is added, it will overwrite the column values.
Here is the end result I am looking to get:
[
//columns
['TaskID','TaskName','StartDate','EndDate','Duration','PercentComplete','Dependecies'],
//rows
['Cite','Create bibliography',null,1420649776903,1,20,'Research'], //missing row
['Complete','Hand in paper',null,1420908976903,1,0,'Cite,Write'],
['Outline','Outline paper',null,1420563376903,1,100,'Research'],
['Research','Find sources',1420390576903,1420476976903,null,100,null],
['Write','Write paper',null,1420822576903,3,25,'Research,Outline']
];
However, I get this.
[
["TaskID","TaskName","StartDate","EndDate","Duration","PercentComplete","Dependecies"],
["Complete","Hand in paper",null,1420908976903.0,1,0,"Cite,Write"],
["Outline","Outline paper",null,1420563376903.0,1,100,"Research"],
["Research","Find sources",1420390576903.0,1420476976903.0,null,100,null],
["Write","Write paper",null,1420822576903.0,3,25,"Research,Outline"]
]
I have tried:
// define the array size based on the datatable
object[,] multiDimensionalArry = new Object[breDataTable.Rows.Count, breDataTable.Columns.Count];
const int columnsArryIndex = 0;
// populate array with column names
if (breDataTable.Columns.Count > 0 && breDataTable.Rows.Count > 0)
{
// loop around columns
for (int i = 0; i <= breDataTable.Columns.Count - 1; i++)
{
// add all the column names
multiDimensionalArry[columnsArryIndex, i] = breDataTable.Columns[i].ColumnName;
}
}
// outer loop - loop backwards from the bottom to the top
// we want to exit the loop, when index == 0 as that is reserved for column names
for (int j = breDataTable.Rows.Count - 1; j >= 0; j--)
{
// get current row items array to loop through
var rowItem = breDataTable.Rows[j].ItemArray;
// inner loop - loop through current row items, and add to resulting multi dimensional array
for (int k = 0; k <= rowItem.Length - 1; k++)
{
multiDimensionalArry[j, k] = rowItem[k];
}
}
You're missing one row when creating your array since the columns name row dosent count as a row
object[,] multiDimensionalArry = new Object[breDataTable.Rows.Count + 1, breDataTable.Columns.Count];
And you need to change your for loop to take into count the extra row
// outer loop - loop backwards from the bottom to the top
// we want to exit the loop, when index == 0 as that is reserved for column names
for (int j = breDataTable.Rows.Count - 1; j >= 0; j--)
{
// get current row items array to loop through
var rowItem = breDataTable.Rows[j].ItemArray;
// inner loop - loop through current row items, and add to resulting multi dimensional array
for (int k = 0; k <= rowItem.Length - 1; k++)
{
multiDimensionalArry[j + 1, k] = rowItem[k];
}
}

Datagrid in delete the row

I am using delete row index to delete a row in datagridview.
But when one row is deleted then datagridview automatically appends next row
first time any index is deleted then itscorrect but at the second time row-1 indexed row is deleted
I am using this code:
for (int i = 0; i < path.Length; i++)
{
lpath.Add(path[i].ToString());
dataGridView1.Rows.RemoveAt(int.Parse(arr[i]));
}
you have to reduce the 'i' after you delete a row when using for loop
See the following code
for (int i = 0; i < path.Length; i++)
{
lpath.Add(path[i].ToString());
dataGridView1.Rows.RemoveAt(int.Parse(arr[i]));
i--; }
As i see it you skew the index off the dataGridView1 the first time.
lets say you have a list with element {1,2,3,4,5} if we now remove index 3 and then 4 we the end up removing 3 and 5 giving us the list {1,2,4} but we wanted to remove 3 and 4 not 3 and 5
what i think you want to do is to get all indexes you want to remove, and the order them and remove from top to bottom so instead of removing 3 an 4 in that order you remove 4 and 3 giving us the list {1,2,5}
List<int> RemoveList = new List<int>();
for (int i = 0; i < path.Length; i++)
{
lpath.Add(path[i].ToString());
RemoveList.Add(int.Parse(arr[i]));
}
//Remove highest index first.
RemoveList.OrderByDescending(a=>a);
for (int i = 0; i < RemoveList.Count; i++)
{
dataGridView1.Rows.RemoveAt(RemoveList[i]);
}
it's a bit weird to increase i within the for loop than decrease it. Why don't you add the items than clear all rows ?
for (int i = 0; i < path.Length; i++) {
lpath.Add(path[i].ToString());
}
dataGridView1.Rows.Clear();

Reorder dataTable columns

I'm reordering my dataTable columns using :
dataTable.Columns[int x].SetOrdinal(int y)
However, I use it for each column and that doesn't to work for me.
For instance :
dataTable.Columns[0].SetOrdinal(1);
dataTable.Columns[1].SetOrdinal(0);
Makes a double inversion...
And in my code, I have to define where each column must be.
Is there any solution to this ?
Thank you.
This process seems easy but not really such easy. The point is whenever you change the Ordinal of a column from x to a lower ordinal a (a < x) then all the columns with ordinals between a and x will be shifted right, if x is changed to a higher ordinal b (b > x) then all the columns with ordinals between x and b wil be shifted left. We must perform some update each time a column's ordinal is changed.
You can prepare a list of your column indices in the order you want, something like this:
List<int> indices = new List<int>{1,2,0,7,4,5,3,6};
for(int i = 0; i < indices.Count; i++){
dataTable.Columns[indices[i]].SetOrdinal(i);
if(indices[i] > i){
for(int j = i; j < indices.Count; j++)
if(indices[j] >= i && indices[j] < indices[i]) indices[j]++;//Right shifted
}
else if(indices[i] < i){
for(int j = i; j < indices.Count; j++)
if(indices[j] >= indices[i] && indices[j] < i) indices[j]--;//Left shifted
}
}
Or you can also prepare a list of your ColumnName in the order you want, something like this:
List<string> columns = new List<string>{"Column2","Column1","Column5","Column3","Column6","Column4"};
//The same code as above
You should change columns order in a loop from array of column name that each column name placed in correct order in array.
For more information go to this link : How to change DataTable columns order

Categories