How to comma-separate a set of strings without the final comma - c#

int rowPosition = 0;
string WorkerName = "";
DataTable dtAllotedManpower = new DataTable();
dtAllotedManpower.Columns.Add("WorkerName");
foreach (GridViewRow row in GridViewTotalManpower.Rows)
{
if (row.RowType == DataControlRowType.DataRow)
{
DataRow drAllotedManpower = dtAllotedManpower.NewRow();
CheckBox chkChild = (CheckBox)GridViewTotalManpower.Rows[rowPosition].FindControl("chkChild");
if (chkChild.Checked == true)
{
WorkerName = Convert.ToString(GridViewTotalManpower.DataKeys[rowPosition]["WorkerName"].ToString()) + "," + WorkerName;
}
rowPosition++;
}
hidfWorker.Value = WorkerName;
I have Written the following piece of code. My hidden field values are coming like this
"HARSH,RIMA,"
But i want the value "HARSH,RIMA" (without ',' after the last word). how to construct the code for that ? . there will be no 'comma' after last word .

Add them to a collection then use string.Join:
var list = new List<string>();
foreach (GridViewRow row in GridViewTotalManpower.Rows) {
// ...other code here...
list.Add(Convert.ToString(GridViewTotalManpower.DataKeys[rowPosition]["WorkerName"].ToString()));
}
hidfWorker.Value = string.Join(", ", list);

You can use string.TrimEnd()
hidfWorker.Value = WorkerName.TrimEnd(',');
This will remove the last comma from the string.

you can use the substring method
hidfWorker.Value=WorkerName.Substring(0,WorkerName.Length-1);

Use StringBuilder instead of string if you are frequently changing the string like in loops, because when you use string it will create new string object every time you changes it,
StringBuilder workerName = new StringBuilder();
And in your loop
workerName.Append(Convert.ToString(GridViewTotalManpower.DataKeys[rowPosition]["WorkerName"].ToString()) + ",");
Then trim last ',' character using TrimEnd method
hidfWorker.Value = workerName.ToString().TrimEnd(',');
Hope this helps.

Related

Updating Datarow from List via for loop. Index was out of bounds

I have two string lists:
currentRow = contains the info that the row should have
currentCol = contains the names of the columns that data from currentRow should go in.
each List contains 25(0-24) items, and is ordered in the same way as the dataRow it should be written to.
I am filling the Lists here, from labels and textboxes on a form:
List<string> currentRow = new List<string>();
List<string> currentCol = new List<string>();
foreach (var c in form11.Controls)
{
if (c.GetType() == typeof(TextBox))
{
var str = c.ToString();
var str1 = str.Substring(35);
currentRow.Add(str1);
}
if (c.GetType() == typeof(Label))
{
var str = c.ToString();
var str1 = str.Substring(34);
currentCol.Add(str1);
}
}
I then select the row in the dataTable that needs to be updated from the 3rd item in currentRow, which is a unique identifier.
var updateRow = arraysDt.Select("SERIAL =" + "'" + currentRow.ElementAtOrDefault(2) + "'");
Now i try to update the row from the items in the Lists here:
for (int i = 0; i < currentRow.Count; i++)
{
//MessageBox.Show(currentCol.ElementAtOrDefault(i).ToString() + " " + currentRow.ElementAtOrDefault(i).ToString());
updateRow[0][currentCol.ElementAtOrDefault(i)] = currentRow.ElementAtOrDefault(i);
}
As soon as it gets inside the for loop i throws a "index was out of bounds of the array" error.
As i said, currentCol contains column names and currentRow is the value.
So when it get here i expect it to find the column name and then update it with the value.
updateRow[0][currentCol.ElementAtOrDefault(i)] = currentRow.ElementAtOrDefault(i);
What am i doing wrong?
I have found out the issue:
"SERIAL =" + "'" + currentRow.ElementAtOrDefault(2) + "'"
will give me this:
SERIAL=' XXXXX'
What i need is:
SERIAL='XXXXX'
so to fix it i did:
string SMnum = currentRow.ElementAt(2).ToString().Replace(" ", string.Empty);
string query = string.Format("SERIAL='{0}'", SMnum.Replace(#"'", "''"));
var updateRow = arraysDt.Select(query);
This removes any white space in the string that i am looking for.

Remove last (empty) entry from StringBuilder object, when exporting to CSV

I want to remove the last (empty) row of a StringBuilder Object
EDIT: The empty row is from the "AllowUserToAddRows" how can i skip it?
c# Forms application
dataGridView1 on form2
I want Export to CSV (separated by semicolon) [btw. it's just one column]
It Could happen, that a previously created CSV is parsed to the dataGridView again
I use a altered solution from here:
Exporting datagridview to csv file
my code
void SaveDataGridViewToCSV(string filename)
{
var sb = new StringBuilder();
var headers = dataGridView1.Columns.Cast<DataGridViewColumn>();
sb.AppendLine(string.Join(";", headers.Select(column => "" + column.HeaderText + ";").ToArray()));
foreach (DataGridViewRow row in dataGridView1.Rows)
{
var cells = row.Cells.Cast<DataGridViewCell>();
sb.AppendLine(string.Join(";", cells.Select(cell => "" + cell.Value + ";").ToArray()));
}
try
{
File.WriteAllText(filename, sb.ToString());
}
catch (Exception exceptionObject)
{
MessageBox.Show(exceptionObject.ToString());
}
}
The sb.ToString looks like this {Coumn;90;90;626;626;;}
The "real" StringBuilder Object as String is: {Coumn;\r\n90;\r\n90;\r\n626;\r\n626;\r\n;}
I want to remove the empty last row.
I tried to parse the stringbuilder to a string, and then remove last semicolon
but with no success (i have problem with the End Of Line.)
string s = sb.ToString();
while (s.EndsWith(";\r\n;") == true)
{
s.Substring(0, s.Length - 5);
}
I tried to remove last element of array, but StingBuilder is no array
I'm stuck.
As i found out the empty set is always exported to the csv.
It's from the ability that the user can input data to the dataGridView, and there is always a empty, active row.
if i disable dataGridView1.AllowUserToAddRows the empty row for userinput is not within the stringbuilder set of data.
void SaveDataGridViewToCSV(string filename)
{
var sb = new StringBuilder();
//SOLUTION disable AllowUserInput to avoid empty set saved to CSV
dataGridView1.AllowUserToAddRows = false;
var headers = dataGridView1.Columns.Cast<DataGridViewColumn>();
sb.AppendLine(string.Join(";", headers.Select(column => "" + column.HeaderText + ";").ToArray()));
foreach (DataGridViewRow row in dataGridView1.Rows)
{
var cells = row.Cells.Cast<DataGridViewCell>();
sb.AppendLine(string.Join(";", cells.Select(cell => "" + cell.Value + ";").ToArray()));
}
try
{
File.WriteAllText(filename, sb.ToString());
}
catch (Exception exceptionObject)
{
MessageBox.Show(exceptionObject.ToString());
}
}
thanks for help!

Searching two DataTables at once for one value

I have two DataTables and I am trying to determine if the tables contain the strings from a list, one string at a time. If the either table contains each string from the list of strings, return true, else false.
Example:
public static bool MyMethod()
{
DataTable table1 = GetMyTable1();
DataTable table2 = GetMyTable2();
List<string> requiredList = new List<string>();
requiredList.Add("foo");
requiredList.Add("bar");
requiredList.Add("foobar");
int counter = 0;
foreach (DataRow row in table1.Rows)
{
if (requiredList.Contains(row["ColumnName"].ToString()))
{
counter++;
}
}
foreach (DataRow row in table2.Rows)
{
if (requiredList.Contains(row["ColumnName2"].ToString()))
{
counter++;
}
}
return (counter == requiredList.Count);
}
The list and the datatables will not have duplicates, and I only care about one column. There won't be any duplicates between tables either.
Is there a more efficient way? Is there a way to search through both datatable's columns at the same time instead of having two foreachs?
If you don't want to loop, there are other options for getting rows from DataTables. You could try a .Select().
foreach(string req in requiredList)
{
DataRow[] rowsTable1 = table.Select("ColumnName LIKE " + req);
DataRow[] rowsTable2 = table.Select("ColumnName LIKE " + req);
counter = counter + rowsTable1.Length + rowsTable2.Length;
}
Of course you can replace the LIKE in the filter string with whatever operator works best for the string comparison you want.
I can't be certain this will be any quicker, but it at least looks shorter.
Not sure if this is the best answer, but you could select matching rows from each table and then count those rows like below:
string listItems = String.Join(",", requiredList);
DataRow[] table1Rows = table1.Select("ColumnName IN (" + listItems + ")");
DataRow[] table2Rows = table2.Select("ColumnName IN (" + listItems + ")");
counter = table1Rows.Length + table2Rows.Length;
What you could try to do is to do a for loop that iterates until max(table1.Rows,table2.Rows), as the previous answer said.
Also put an if statement to take care of being out of bounds

CSV Line Breaks

I'm building a csv file from database values. When I open the csv in excel everything is on one row. To counter this I've added either \n or \r after each row. Now when I open in excel starting at the second row there is an empty value throughout the rest of the first column.
IE:
value 1, value 2, value 3
, value 1, value 2, value 3
, value 1, value 2, value 3
, value 1, value 2, value 3
I can add a newline or return before the first value, but then there is an empty row and column. How can I get this lined up?
My code:
try
{
connection = new iDB2Connection(connectionString);
connection.Open();
command = new iDB2Command(commandString, connection);
reader = command.ExecuteReader();
var dt = new DataTable();
dt.Load(reader);
List<string> CsvList = new List<string>();
foreach (DataRow row in dt.Rows)
{
foreach (var item in row.ItemArray)
{
CsvList.Add(item.ToString());
}
if (i == 1)
{
CsvList.Add(" ");
CsvList.Add("Customer Service");
CsvList.Add("Customer Service Representative" + "\r");
// \r and \n not working
}
}
System.IO.StreamWriter streamWriter;
streamWriter = new System.IO.StreamWriter(fileName, true);
string CsvString = string.Join(",", CsvList.ToArray());
streamWriter.WriteLine(CsvString);
streamWriter.Close();
Console.WriteLine("File saved as " + fileName);
i++;
}
It'll be a heck of a lot easier if you just build up a list of lines, rather than a flattened list of single values. Since you've flattened your list already when you use Join you're putting commas after newlines values, for example.
Instead join together the values for each line, and then just keep track of the entire lines:
foreach (DataRow row in dt.Rows)
{
CsvList.Add(string.Join(",", row.ItemArray));
}
Now that you have a list of lines, we can just use File.AppendAllLines to simply and easily write out all of the lines to the end of the file:
File.AppendAllLines(fileName, CsvList);
Or, if you would like to stream the results to the file rather than copying all of the data over to a list and holding it all in memory at once, you can do this:
var lines = dt.AsEnumerable()
.Select(row => string.Join(",", row.ItemArray));
File.AppendAllLines(fileName, lines);
Instead of creating an array and handling adding new-lines yourself, use a StringBuilder, and commit each row one at a time:
var sb = new StringBuilder();
foreach (DataRow row in dt.Rows)
{
List<string> csvList = new List<string>();
foreach (var item in row.ItemArray)
{
csvList.Add(item.ToString());
}
if (i == 1)
{
csvList.Add(" ");
csvList.Add("Customer Service");
csvList.Add("Customer Service Representative");
}
sb.WriteLine(string.Join(",", csvList));
}
System.IO.StreamWriter streamWriter;
streamWriter = new System.IO.StreamWriter(fileName, true);
streamWriter.WriteLine(sb.ToString());
streamWriter.Close();
Console.WriteLine("File saved as " + fileName);

Converting DataSet/DataTable to CSV

Please let me know, if there any way to generate CSV files from a DataTable or DataSet? To be specific, without manually iterating through rows of DataTable and concatenating.
Please help
There are several ways to do that.
One of the simplest (IMO) is using FileHelpers Library
FileHelpers.CsvEngine.DataTableToCsv(dataTable, filename);
A relative simple, compact and quite flexible solution could be the following extension method:
public static string ToCsv(this DataTable table, string colSep = "", string rowSep = "\r\n")
{
var format = string.Join(colSep, Enumerable.Range(0, table.Columns.Count)
.Select(i => string.Format("{{{0}}}", i)));
return string.Join(rowSep, table.Rows.OfType<DataRow>()
.Select(i => string.Format(format, i.ItemArray)));
}
Please note that this solution could cause problems with huge amounts of data, in which case you should stream the output. Quoting and formatting would of course make the code more complex.
There is, I hope, also a possible way for doing that:
static void Main(string[] args)
{
DataTable dt = new DataTable("MyTable");
dt.Columns.Add("Id", typeof(int));
dt.Columns.Add("Name", typeof(string));
DataRow dr1 = dt.NewRow();
dr1["Id"] = 1;
dr1["Name"] = "John Smith";
dt.Rows.Add(dr1);
DataRow dr2 = dt.NewRow();
dr2["Id"] = 2;
dr2["Name"] = "John West";
dt.Rows.Add(dr2);
List<DataRow> list = dt.AsEnumerable().ToList();
var strlist = from dr in list
select dr[0] + ", " + dr[1];
var csv = string.Join(Environment.NewLine,strlist);
Console.WriteLine(csv);
}
//Dataset To Xls
ExportDataSetToCsvFile(DS,#"C:\\");
internal static void ExportDataSetToCsvFile(DataSet _DataSet, string DestinationCsvDirectory)
{
try
{
foreach (DataTable DDT in _DataSet.Tables)
{
String MyFile = #DestinationCsvDirectory + "\\_" + DDT.TableName.ToString() + DateTime.Now.ToString("yyyyMMddhhMMssffff") + ".csv";//+ DateTime.Now.ToString("ddMMyyyyhhMMssffff")
using (var outputFile = File.CreateText(MyFile))
{
String CsvText = string.Empty;
foreach (DataColumn DC in DDT.Columns)
{
if (CsvText != "")
CsvText = CsvText + "," + DC.ColumnName.ToString();
else
CsvText = DC.ColumnName.ToString();
}
outputFile.WriteLine(CsvText.ToString().TrimEnd(','));
CsvText = string.Empty;
foreach (DataRow DDR in DDT.Rows)
{
foreach (DataColumn DCC in DDT.Columns)
{
if (CsvText != "")
CsvText = CsvText + "," + DDR[DCC.ColumnName.ToString()].ToString();
else
CsvText = DDR[DCC.ColumnName.ToString()].ToString();
}
outputFile.WriteLine(CsvText.ToString().TrimEnd(','));
CsvText = string.Empty;
}
System.Threading.Thread.Sleep(1000);
}
}
}
catch (Exception Ex)
{
throw Ex;
}
}
So this is a fairly bizarre solution, but it works faster than most as it makes use of the JSON.net library's serialization. This speeds the solution up significantly.
Steps:
Create array of every column name in the data table, should be
simple
Use JSON.net to convert datatable to a json string
string json = JsonConvert.SerializeObject(dt, Formatting.None);
Begin making use of the Replace function on c# strings and strip the
json string of all json formatting.
json = json.Replace("\"", "").Replace("},{", "\n").Replace(":", "").Replace("[{", "").Replace("}]", "");
Then use the array from step 1 to remove all column names from the
json string. You are left with a csv formatted string.
Consider using the array created in step 1 to add the column names
back in as the first row in csv format.

Categories

Resources