I'm trying to print the content of a DataTable, starting with the column headers, followed by the content of the table tupples.
output.Add($"Table : [{dataTable.TableName}]");
string strColumnNames = "";
foreach (DataColumn col in dataTable.Columns)
{
if (strColumnNames == "")
strColumnNames = col.ColumnName.PadLeft(col.MaxLength - col.ColumnName.Length); // (*)
else strColumnNames = strColumnNames + "|" +
col.ColumnName.PadLeft(col.MaxLength - col.ColumnName.Length); // (*)
}
output.Add($"[{strColumnNames}]");
foreach (DataRow dataRow in dataTable.Rows)
{
string temp = "";
for (int i = 0; i < dataRow.ItemArray.Count(); i++)
{
if (i == 0)
temp = dataRow.ItemArray[i].ToString(); // (**)
else temp += "|" + dataRow.ItemArray[i].ToString(); // (**)
}
output.Add($"[{temp}]");
}
The (*) parts in this code are using the MaxLength property of the DataColumns maximum length in order to get a column-like output.
I would like to do the same in the (**) parts, but I don't know how to access the corresponding DataColumn, starting from the dataRow object.
Does anybody have an idea?
Thanks in advance
You already have the dataTable instance available. dataTable.Columns[i] should give you the appropriate DataColumn.
Datatable has already been instantiated here. If you want to print the datacolumn you should use dataTable.Column[i] for the appropriate column.
Related
My question is actually more about optimizing something I already have working.
I'm having a hard time believing there isn't a better way to do this with a LINQ query or lambda expression, so I thought I'd try here.
Each of my datatable rows has an item number and 43 quantity columns, that each correspond with a specific day. What I'm trying to do is take each row, and find the first quantity column that is greater than 0 and return that column name. My solution does work, but I'd really like to make it more efficient:
foreach (DataRow r in dt.Rows)
{
for (int i = 3; i <= dt.Columns.Count - 1; i++)
{
tempCol = dt.Columns(i).ColumnName.ToString();
rowValue = Convert.ToInt32(r(tempCol));
if (rowValue > 0)
{
tempCol = tempCol.Replace("Apat", "");
break;
}
}
var FirstAvailableDate = WorkDate.AddDays((dec)tempCol).ToShortDateString;
//use data in someway
}
Thanks for any suggestions ahead of time!!
the current code, each row * each column
get name of column
store it in variable
in match case perform String.Replace
my suggestion:
var allCols = dt.Columns
.Cast<DataColumn>()
.Select(col => col.ColumnName.Replace("Apat", ""))
.ToArray();
foreach (DataRow r in dt.Rows)
{
var firstCol =
r.ItemArray.Select((cell, position) => Tuple.Create(Convert.ToInt32(cell), position))
.FirstOrDefault(tuple => tuple.Item1 > 0);
if(firstCol == null) continue;
var colName = allCols[firstCol.Item2];
var FirstAvailableDate = WorkDate.AddDays((dec)colName).ToShortDateString;
//use data in someway
}
Please change following code
Tuple.Create(Convert.ToInt32(position), cell)
var colName = allCols[firstCol.Item1];
Working fine...!!!
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]);
}
}
}
In my application i am filtering a datatable using a filter expression and am getting a DataRow which matches the condition.Now i want to check if the value of particular column exists in any row of DataRow array.
Code:
string FilterCond1 = "id=" + getId;
DataRow[] myrow = DataTable.Select(FilterCond1);
if (myrow.Length > 0)
{
//check for size=28 in DataRow[]
}
else
{
}
I have column size in the datatable DataTable and i want to check if any row of the DataRow array has a value 28 in the column size.How can i go about it?
Try this
string FilterCond1 = "id=" + getId;
DataRow[] myrow = DataTable.Select(FilterCond1);
if (myrow.Length > 0)
{
for(int i = 0; i < myrow.Length; i ++)
{
if(myrow[i]["size"].ToString() == "28")
{
// YOUR CODE HERE
}
}
}
else
{
}
EDIT
Just add the condition to your filter.
string FilterCond1 = "id=" + getId + " AND size=28";
Then you don't need the if(myrow[i]["size"].ToString() == "28") as you know the rows in the array are the one you want.
You can use column collection to access particular column value within row.
if(myrow[rowIndex]["ColoumnName"].ToString() == "somevalue")
Where row index could from zero to length-1
Edit based on comments, you can put multiple condition on column in select, check it here, and may not need to iterate.
string FilterCond1 = "id=" + getId + " AND size = " + 28;
DataRow[] myrow = dt.Select(FilterCond1);
To iterate through rows collection
for(int i=0; i < myrow.Length; i++)
{
if(myrow[i]["size"].ToString() == "28")
{
//your code
}
}
First you should aiterate through all rows using foreach then use the below code..
if(myrow[row]["size"] == 28)
or
int ColIndex = 3; // replace 3 with ur co. index
if(myrow[row][ColIndex] == 28)
public void GenerateDetailFile()
{
if (!Directory.Exists(AppVars.IntegrationFilesLocation))
{
Directory.CreateDirectory(AppVars.IntegrationFilesLocation);
}
DateTime DateTime = DateTime.Now;
using (StreamWriter sw = File.CreateText(AppVars.IntegrationFilesLocation +
DateTime.ToString(DateFormat) + " Detail.txt"))
{
DataTable table = Database.GetDetailTXTFileData();
foreach (DataRow row in table.Rows)
{
sw.WriteLine(row);
}
}
}
Not sure what I'm missing here but I think it might be the column name which I'm not sure how to set it up.
This is working fine, except, when it writes to the text file, it's writing this:
System.Data.DataRow
System.Data.DataRow
System.Data.DataRow
System.Data.DataRow
System.Data.DataRow
System.Data.DataRow
System.Data.DataRow
System.Data.DataRow
System.Data.DataRow
System.Data.DataRow
Can anyone give me a hand?
When you try to print out a DataRow like that, it is calling Object.ToString(), which simply prints out the name of the type. What you want to do is something like:
sw.WriteLine(String.Join(",", row.ItemArray));
This will print a comma separated list of all of the items in the DataRow.
Something like:
sw.WriteLine(row["columnname"].ToString());
would be more appropriate.
The below code will let you to write text file each column separated by '|'
foreach (DataRow row in dt.Rows)
{
object[] array = row.ItemArray;
for (int i = 0; i < array.Length - 1; i++)
{
swExtLogFile.Write(array[i].ToString() + " | ");
}
swExtLogFile.WriteLine(array[array.Length - 1].ToString());
}
Reference link
There is no "natural" string representation for a DataRow. You need to write it out in whatever format you desire, i.e., comma-separated list of values, etc. You can enumerate the columns and print their values, for instance:
foreach (DataRow row in table.Rows)
{
bool firstCol = true;
foreach (DataColumn col in table.Columns)
{
if (!firstCol) sw.Write(", ");
sw.Write(row[col].ToString());
firstCol = false;
}
sw.WriteLine();
}
You need to write the columns from each DataRow. Currently you are writing the DataRow object that is dataRow.ToString() hence you get string name "System.Data.DataRow" of dataRow in your file
foreach(DataRow row in table.Rows)
{
foreach(DataColumn column in table.Columns)
{
sw.WriteLine(row[column]);
}
}
Try this:
To write the DataTable rows to text files in the specific directory
var dir = #"D:\New folder\log"; // folder location
if (!Directory.Exists(dir)) // if it doesn't exist, create
Directory.CreateDirectory(dir);
foreach (DataRow row in dt.Rows)
{
for (int i = 0; i < dt.Columns.Count; i++)
{
result.Append(row[i].ToString());
result.Append(i == dt.Columns.Count - 1 ? "\n" : ",");
}
result.AppendLine();
}
string path = System.IO.Path.Combine(dir, "item.txt");
StreamWriter objWriter = new StreamWriter(path, false);
objWriter.WriteLine(result.ToString());
objWriter.Close();
I am trying to find a fast way to find a string in all datatable columns!
Followed is not working as I want to search within all columns value.
string str = "%whatever%";
foreach (DataRow row in dataTable.Rows)
foreach (DataColumn col in row.ItemArray)
if (row[col].ToString() == str) return true;
You can use LINQ. It wouldn't be any faster, because you still need to look at each cell in case the value is not there, but it will fit in a single line:
return dataTable
.Rows
.Cast<DataRow>()
.Any(r => r.ItemArray.Any(c => c.ToString().Contains("whatever")));
For searching for random text and returning an array of rows with at least one cell that has a case-insensitive match, use this:
var text = "whatever";
return dataTable
.Rows
.Cast<DataRow>()
.Where(r => r.ItemArray.Any(
c => c.ToString().IndexOf(text, StringComparison.OrdinalIgnoreCase) > 0
)).ToArray();
If you want to check every row of every column in your Datatable, try this (it works for me!).
DataTable YourTable = new DataTable();
// Fill your DataTable here with whatever you've got.
foreach (DataRow row in YourTable.Rows)
{
foreach (object item in row.ItemArray)
{
//Do what ya gotta do with that information here!
}
}
Don't forget to typecast object item to whatever you need (string, int etc).
I've stepped through with the debugger and it works a charm. I hope this helps, and good luck!
This can be achieved by filtering. Create a (re-usable) filtering string based on all the columns:
bool UseContains = false;
int colCount = MyDataTable.Columns.Count;
string likeStatement = (UseContains) ? " Like '%{0}%'" : " Like '{0}%'";
for (int i = 0; i < colCount; i++)
{
string colName = MyDataTable.Columns[i].ColumnName;
query.Append(string.Concat("Convert(", colName, ", 'System.String')", likeStatement));
if (i != colCount - 1)
query.Append(" OR ");
}
filterString = query.ToString();
Now you can get the rows where one of the columns matches your searchstring:
string currFilter = string.Format(filterString, searchText);
DataRow[] tmpRows = MyDataTable.Select(currFilter, somethingToOrderBy);
You can create a routine of search with an array of strings with the names of the columns, as well:
string[] elems = {"GUID", "CODE", "NAME", "DESCRIPTION"};//Names of the columns
foreach(string column in elems)
{
string expression = string.Format("{0} like '%{1}%'",column,
txtSearch.Text.Trim());//Search Expression
DataRow[] row = data.Select(expression);
if(row.Length > 0) {
// Some code here
} else {
// Other code here
}
}
You can get names of columns by using ColmunName Method. Then, you can search every column in DataTable by using them. For example, follwing code will work.
string str = "whatever";
foreach (DataRow row in dataTable.Rows)
{
foreach (DataColumn column in dataTable.Columns)
{
if (row[column.ColumnName.ToString()].ToString().Contains(str))
{
return true;
}
}
}
You can create a filter expression on the datatable as well. See this MSDN article. Use like in your filter expression.
string filterExp = "Status = 'Active'";
string sortExp = "City";
DataRow[] drarray;
drarray = dataSet1.Customers.Select(filterExp, sortExp, DataViewRowState.CurrentRows);
for (int i=0; i < drarray.Length; i++)
{
listBox1.Items.Add(drarray[i]["City"].ToString());
}