How to increment multiple loops properly in C# - c#

I am running into a problem where I am not comparing the correct data points because only part of my test is iterating.
//for each row from csv
foreach (DataRow dataRow in csvDataTable.Rows)
{
//for each cell from csv row
foreach (var csvItem in dataRow.ItemArray)
{
//for each audiogram
for (int i = 0; i < audioGramData.Count(); i++)
{
//for each stimulus frequency
for (int e = 0; e < audioGramData.Count(); e++)
{
string stimLevel = audioGramData[i].ToList()[e]["StimulusLevel"].ToString();
if (csvItem.ToString() != stimLevel)
{
return false;
}
}
}
}
}
return true;
The first pass of the test properly compares the first cell from a csv file to a the proper field from a JSON object. However, on the second pass, only the stimLevel variable is incremented.
If there were 3 rows in the CSV file, 3 columns in the CSV file, and 3 stimLevels in the JSON object, the flow of the test should be like this:
((Compare first csvItem to first stimLevel
csvItem++
stimLevel++)x3
DataRow++
audiogram++)x3
The audioGramData 2D array is created by first converting a dataTable containing JSON into a JSON object like this:
sqlAdapter.Fill(sqlDataTable);
Conn.Close();
JObject someObject = JObject.Parse(sqlDataTable.Rows[0].ItemArray[0].ToString());
var audioGramData = (JArray)someObject["HIMSAAudiometricStandard"]["ToneThresholdAudiogram"];

This was resolved by getting rid of the two extra 4 loops and iterating i and e outside of each of the for each loops.
int i =0;
int e =0;
//for each row from csv
foreach (DataRow dataRow in csvDataTable.Rows)
{
//for each cell from csv row
foreach (var item in dataRow.ItemArray)
{
string stimlevel = audioGramData[i].ToList()[1].ToList()[0].ToList()[e]["StimulusLevel"].ToString();
stimlevel = stimlevel.Remove(stimlevel.Length -2);
if (item.ToString() != stimlevel)
{
return false;
}
e++;
}
i++;
}
return true;

Related

ClosedXml Excel Add multiple values to Rows

Trying to add values from an array string[] to a row in Excel.
When I'm trying to use dt.Rows.Add(string[i]) it is added to the Excel sheet. The problem is it is added vertically, which is quite obvious because I'm only adding one item to the row and then insert a new row. My question now is how to add every item from the string[] to one row so that my data is displayed horizontally.
For example string[] values = {"a","b","c","d"};
The output I have at the moment:
a
b
c
d
The output I want:
a b c d (each in a different cell).
A1 = a
B1 = b
...
I've already been able to add columns to the worksheet, I only need my data to be right.
This is my code for now.
//Add columns
dt.Columns.AddRange(columns.Select(c => new DataColumn(c.ToString())).ToArray());
List<string> temp;
string[] values;
for (int i = 0; i < 7; i++)
{
temp = new List<string>();
temp.Add(timeStamps[i].ToString());
foreach (var item in tagCollection)
{
if (timeStamps[i].Date == item.time)
{
temp.Add(item.min);
temp.Add(item.max);
temp.Add(item.avg);
}
}
int index = 0;
values = new string[temp.Count];
foreach (var item in temp)
{
values[index] = item;
dt.Rows.Add(values[index]);
index++;
}
}
//Convert datatable to dataset and add it to the workbook as worksheet
ds.Tables.Add(dt);
workbook.Worksheets.Add(ds);
The solution may go through the following:
string[] cars = { "Volvo", "BMW", "Mazda" };
table.Rows.Add(cars[0].ToString(), cars[1].ToString(), cars[2].ToString());
Output:
Just need to adapt to your own code.
You've to guarantee that your Datasheet has the columns needed to display all data in the same row. If you didn't do that, for sure it will generate a matrix error.
This works for me. I Changed the foreach loop and discoverd that there was a NewRow() method.
int index = 0;
values = new string[temp.Count];
DataRow newRow;
newRow = dt.NewRow();
foreach (var item in temp) {
values[index] = item;
newRow.ItemArray = temp.Cast<object>().ToArray();
index++;
}
dt.Rows.Add(newRow);

How can I save rearranged column positions when reading out a DataGrid?

I have a DataGrid implemented in a WPF-window inside a VSTO-AddIn, which is supposed to preview data to the user before it is pasted to an existing Excel-sheet. The CanUserSortColumns-Property is set to true, so the user is able to rearrange the columns before they are read out and pasted to the sheet. However, when I read out the DataRows from the DataGrid, as shown below, the columns are back in their original position.
object[,] dataArray = new object[allRows, allCols];
for (int r = 0; r < allRows; r++)
{
DataRow row = ClientGrid.Rows[r];
for (int c = 0; c < allCols; c++)
{
dataArray[r, c] = row[c];
}
}
Here is my question: Is there any way to fix this the quick way or at least to track the changes of column display indices in order to rearrange the column order in the code with every change of the columns display order?
I've already tried working something out with the DisplayIndex-property but I did not quite get the hang of the numbers it spits out.
You could order the columns by the DisplayIndex property and use reflection to export the values using reflection, e.g.:
public static void ExportUsingRefection(this DataGrid grid)
{
if (grid.ItemsSource == null || grid.Items.Count.Equals(0))
throw new InvalidOperationException("You cannot export any data from an empty DataGrid.");
IEnumerable<DataGridColumn> columns = grid.Columns.OrderBy(c => c.DisplayIndex);
ICollectionView collectionView = CollectionViewSource.GetDefaultView(grid.ItemsSource);
foreach (object o in collectionView)
{
if (o.Equals(CollectionView.NewItemPlaceholder))
continue;
foreach (DataGridColumn column in columns)
{
if (column is DataGridBoundColumn)
{
string propertyValue = string.Empty;
/* Get the property name from the column's binding */
BindingBase bb = (column as DataGridBoundColumn).Binding;
if (bb != null)
{
Binding binding = bb as Binding;
if (binding != null)
{
string boundProperty = binding.Path.Path;
/* Get the property value using reflection */
PropertyInfo pi = o.GetType().GetProperty(boundProperty);
if (pi != null)
{
object value = pi.GetValue(o);
if (value != null)
propertyValue = value.ToString();
}
}
}
//...
}
}
}
}
Please refer to the following blog post for more information.
How to export data from a DataGrid in WPF: https://blog.magnusmontin.net/2013/09/29/export-data-from-a-datagrid/
I ended up doing the following:
Reading out the DisplayIndex-Property and the initial position of each column and ordering the tuples by the DisplayIndex-Property afterwards
var columnIndices = new List<Tuple<int,int>>();
var colCounter = 0;
foreach (var col in myDataGrid.Columns)
{
columnIndices.Add(Tuple.Create(col.DisplayIndex, colCounter));
colCounter += 1;
}
var sortedColumns = columnIndices.OrderBy(x => x.Item1).ToList();
Creating an empty DataTable and adding the original DataGrid's columns to it. Then I set the new DataTable's DataRow's cells equal to the cells of the DataRows of the original DataGrid.
var myDataTable = new DataTable();
foreach (var index1 in sortedColumns)
{
var columnName = myDataGrid.Columns[index1.Item2].ColumnName;
myDataTable.Columns.Add(columnName, myDataGrid.Columns[index1.Item2].DataType);
}
foreach (DataRow dr in myDataGrid.Rows)
{
var itemArray = new object[allCols];
var indexer = 0;
foreach (var index2 in sortedColumns)
{
itemArray[indexer] = dr[index2.Item2];
indexer += 1;
}
myDataTable.Rows.Add(itemArray);
}

Check empty rows in datatable in Visual Studio 2005, no LINQ

I've uploaded data to a datatable from a excel file. Whats the best way to check empty rows in datatable. NB: Need solution for Visual Studio 2005. Cant use linq.
foreach (DataRow row in result.Rows)
{
//check if row is empty
//if not continue processing data
//else remove the row from datatable
}
Currently the solution in my mind is inside foreach loop, put another foreach loop and check each column. If all columns are null, remove the row from datatable.
Is there any other best method. Does the above method takes more time to execute as there is another for each loop. There will be lots of rows in the datatable.
Edited:
I've got one code:
private bool checkIfRowEmpty(DataRow row)
{
var r = (DataRow)row;
int emptyCount = 0;
int itemArrayCount = r.ItemArray.Length;
foreach (var i in r.ItemArray) if (string.IsNullOrWhiteSpace(i.ToString())) emptyCount++;
if (emptyCount == itemArrayCount) return false;
else return true;
}
Is this okay? Or should I use any solution from below? Which one is good?
Here is one approach - to iterate through all rows and all columns
DataTable table = new DataTable();
List<int> rowsToRemove = new List<int>();
for (int i = 0; i < table.Rows.Count; i++)
{
DataRow row = table.Rows[i];
foreach (DataColumn col in row.Table.Columns)
{
bool skip = false;
if (row[col] != null)
{
//this column is not null, so mark skip flag as true
skip = true;
}
if (skip)
//this row should be skipped because it has at least one column that isn't null
break;
else
rowsToRemove.Add(i);
//mark this row's index for deletion
}
}
//loop through list in reverse order and remove rows by their index
for (int i = rowsToRemove.Count; i > 0; i--)
table.Rows.RemoveAt(i);
Best solution I can think of is the following one:
public bool IsRowEmpty(DataRow row)
{
if (row == null)
return true;
foreach(var value in row.ItemArray)
{
if (value != null)
return false;
}
return true;
}
Then from your main code:
foreach (DataRow row in result.Rows)
{
if(!IsRowEmpty(row))
{
// Row is not empty.
}
}
Hello,
You can simply achive this using DataView : like this -
DataView dv = yourTable.DefaultView;
dv.Sort = "column_1,column_2";
DataTable dtNew = dv.ToTable(true, "column_1", "column_2",...,"column_n"); // please mention all columns here
dtNew.Rows.RemoveAt(0);

Don't split the string if contains in double marks

I have a text delimeted file need to convert into datatable. Given the text something like this :
Name,Contact,Email,Date Of Birth,Address
JOHN,01212121,hehe#yahoo.com,1/12/1987,"mawar rd, shah alam, selangor"
JACKSON,01223323,haha#yahoo.com,1/4/1967,"neelofa rd, sepang, selangor"
DAVID,0151212,hoho#yahoo.com,3/5/1956,"nora danish rd, klang, selangor"
And this is how i read the text file in C#
DataTable table = new DataTable();
using (StreamReader sr = new StreamReader(path))
{
#region Text to csv
while (!sr.EndOfStream)
{
string[] line = sr.ReadLine().Split(',');
//table.Rows.Add(parts[0], parts[1], parts[2], parts[3], parts[4], parts[5]);
if (IsRowHeader)//Is user want to read first row as the header
{
foreach (string column in line)
{
table.Columns.Add(column);
}
totalColumn = line.Count();
IsRowHeader = false;
}
else
{
if (totalColumn == 0)
{
totalColumn = line.Count();
for (int j = 0; j < totalColumn; j++)
{
table.Columns.Add();
}
}
// create a DataRow using .NewRow()
DataRow row = table.NewRow();
// iterate over all columns to fill the row
for (int i = 0; i < line.Count(); i++)
{
row[i] = line[i];
}
// add the current row to the DataTable
table.Rows.Add(row);
}
}
The column is dynamic, the user can add or remove the column on the text file. So I need to check how many column and set to datatable, after that I will read for each line, set value to datarow and then add row to table.
If I don't remove the semicolon inside the double marks, it will show the error "Cannot find column 5" because on the first line is only 4 column (start from 0).
What the best way to deal with text delimited?
Don't try and re-invent the CSV-parsing wheel. Use the parser built into .NET: Microsoft.VisualBasic.FileIO.TextFieldParser
See https://stackoverflow.com/a/3508572/7122.
No, just don't. Don't try and write your own CSV parser - there's no reason to do it.
This article explains the problem and recommends using FileHelpers - which are decent enough.
There is also the Lumenworks reader which is simpler and just as useful.
Finally apparently you can just use DataSets to link to your CSV as described here. I didn't try this one, but looks interesting, if probably outdated.
I usually go with something like this:
const char separator = ',';
using (var reader = new StreamReader("C:\\sample.txt"))
{
var fields = (reader.ReadLine() ?? "").Split(separator);
// Dynamically add the columns
var table = new DataTable();
table.Columns.AddRange(fields.Select(field => new DataColumn(field)).ToArray());
while (reader.Peek() >= 0)
{
var line = reader.ReadLine() ?? "";
// Split the values considering the quoted field values
var values = Regex.Split(line, ",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)")
.Select((value, current) => value.Trim())
.ToArray()
;
// Add those values directly
table.Rows.Add(values);
}
// Demonstrate the results
foreach (DataRow row in table.Rows)
{
Console.WriteLine();
foreach (DataColumn col in table.Columns)
{
Console.WriteLine("{0}={1}", col.ColumnName, row[col]);
}
}
}

Add specific rows from dataGridView depending on search value

Following issue:
I have a datatable and a list which contains specific values.
routIds = col1Items.Distinct().ToList();
String searchValue = String.Empty;
int rowIndex = -1;
for (int i = 0; i < routIds.Count; i++)
{
searchValue = routIds[i];
foreach (DataGridViewRow row in form1.dataGridView5.Rows)
{
if (row.Cells[form1.routingIdBox.Text].Value != null) // Need to check for null if new row is exposed
{
if (row.Cells[form1.routingIdBox.Text].Value.ToString().Equals(searchValue))
{
rowIndex = row.Index;
foreach (DataGridViewColumn column in form1.dataGridView5.Columns)
dtRout.Columns.Add(column.Name);
for (int k = 0; k < form1.dataGridView5.Rows.Count; k++)
{
dtRout.Rows.Add();
for (int j = 0; j < form1.dataGridView5.Columns.Count; j++)
{
datTable.Rows[k][j] = form1.dataGridView5.Rows[rowIndex].Cells[j].Value;
}
}
}
}
}
}
I want to search the first column from my datagridview and check if it matches a specific value (from my array - routIds). If yes then I want to add the whole row into a datatable but I don't know how this works exactly. Tried around but I get exceptions (specific row not found).
Assuming you have a DataTable as your underlying DataSource. I would not iterate through the DataGridViewRows.
DataTable dataSource = dataGridView.DataSource as DataTable; // if it is a DataTable. If not, please specify in your question
// let's make a DataTable, which is a copy of your DataSource
DataTable dataTableFoundIds = new DataTable();
foreach (DataColumn column in dataSource.Columns)
dataTableFoundIds.Columns.Add(column.ColumnName, column.DataType);
// iterate through your routeIds
foreach (int id in routeIds)
{
var row = dataSource.AsEnumerable().FirstOrDefault(item => item["col1"].Equals(id)); // take the first row in your DataSource that matches your routeId
if (row != null)
{
dataTableFoundIds.Rows.Add(row.ItemArray); // if we find something, insert the whole row of our source table
}
}
Hope this helps!
UPDATE: if you want to find all occurances:
foreach (int id in routeIds)
{
var rows = dataSource.AsEnumerable().Where(item => item["col1"].Equals(id)); // take all rows in your DataSource that match your routeId
foreach(var row in rows)
{
dataTableFoundIds.Rows.Add(row.ItemArray); // if we find something, insert the whole row of our source table
}
}

Categories