I want to remove unwanted columns from a datatable and arrange the order of the columns in pre-defined order
For example, my table columns are like below,
Col2|Col1|Col3|Test|Test1|Col5|Col4|Some col name|Col6
I want to remove Test, Test1 and Some col name and reorder by datatable into below format
Col1|Col2|Col3|Col4|Col5|Col6
// I need the below columns
List<string> tableColumns = new List<string>();
tableColumns.Add("Col1");
tableColumns.Add("Col2");
tableColumns.Add("Col3");
tableColumns.Add("Col4");
tableColumns.Add("Col5");
tableColumns.Add("Col6");
List<DataColumn> tblColumns = MyDataTable.Columns.Cast<DataColumn>().ToList();
//Remove unwanted columns
foreach (DataColumn col in tblColumns)
{
if (!tableColumns.Contains(col.ColumnName.Trim()))
{
MyDataTable.Columns.Remove(col);
}
}
Now how do I re-order the columns in the below order?
Col1|Col2|Col3|Col4|Col5|Col6
I tried like in the below code, but it fails if all items in tableColumns doesn’t exists in datatable.
Also some times data table column name has some empty space (ex “ Col1”)
foreach (var col in tableColumns)
{
MyDataTable.Columns[col].SetOrdinal(tableColumns.IndexOf(col));
}
Which is the best way to remove unwanted columns and re-arrange the columns?
After you remove the unwanted columns, here is how you can order them:
int index = 0;
foreach (var col in
MyDataTable.Columns
.Cast<DataColumn>()
.OrderBy(x => tableColumns.IndexOf(x.ColumnName))
.ToList())
{
col.SetOrdinal(index);
index ++;
}
This selects the columns from the DataTable, and orders them by their corresponding index in the tableColumns list.
Then it invokes SetOrdinal on each one of them, incrementing the index each time.
I think your columns may have random order like Col2,Col1,Col3. And you want to rearrange and remove the unwanted columns, like Col1,Col2,Col3.
string[] srr = new string[]{"Col2","Col1","Col3","Test","Test1","Col6","Col4","Some col name","Col5"};
DataTable MyDataTable = new DataTable();
foreach(string col in srr)
{
MyDataTable.Columns.Add(col);
}
List<string> arrayNames = (from DataColumn x in MyDataTable.Columns
select x.ColumnName).ToList();
foreach(var col in arrayNames)
{
if(!col.Contains("Col"))
{
MyDataTable.Columns.Remove(col);
}
else
{
int result = Convert.ToInt32(Regex.Match(col.ToString(), #"\d+$").Value);
MyDataTable.Columns[col].SetOrdinal(result-1);
}
}
This will remove the columns like Test,Test1,some col name ie. columns which don't have the word "Col" (change the logic according to your program). Then by using regex it will extract the numbers from column names. ie 1 from "Col1", then rearrange the columns according to it.
Related
I have more than 9000 rows and 18 columns in my datagridview. I have to read the columns from an external datatable. If I find a match between column names, I have to copy all values from the datatable column into the datagridview column. My problem is, I cannot iterate over these rows for 18 times for more than 9000 rows and write for every iteration the value in the datagridview cell because it is too slow. Is there any valid alternative?
I add some code below so that you can understand better my question. Here I'm iterating the columns first, then the rows. Sorry for the indentation but I'm having problems in copy paste code on StackOverflow.
dgvMappatura is my dataGridView, dtExcel is my DataTable
foreach (DataColumn col in dtExcel.Columns)
{
if (col.ColumnName.Equals(nome_colonna_origine))
{
foreach (DataRow drExcel in dtExcel.Rows)
{
// some code to add values to datagridview from the datatable column
}
}
}
See if following is faster :
DataTable dt = new DataTable();
foreach (DataRow row in dt.AsEnumerable())
{
var matches = row.ItemArray.Select((x, i) => new { name = x.ToString(), index = i }).GroupBy(x => x.name).Where(x => x.Count() > 1).ToArray();
}
I have a DataTable in C#, where I have a monthly report Like this:
I have just shown 4 dates as of now. All these date come from a PIVOT Table in SQL. Whereas, I have added the Totals column programmatically.
What I want is I want to count the number of A's, B's, and C's in Total A's, Total B's, and Total C's Field.
This is what I tried so far
DataTable report = DataAccess.GetDataInDataTable(ConstantFieldsModel.PRIMARYCONNECTION, "usp_GetReport", CommandType.StoredProcedure, param);
report.Columns.Add("Total As", typeof(int)).SetOrdinal(2);// adds 'Total' field at position 5
report.Columns.Add("Total Bs", typeof(int)).SetOrdinal(3);
report.Columns.Add("Total Cs", typeof(int)).SetOrdinal(4);
foreach (DataRow row in report.Rows)
{
int sum = 0;
foreach (DataColumn col in report.Columns)
{
if (!row.IsNull(col))
{
string val = row[col].ToString();
int a;
if (int.TryParse(val, out a))
{
sum += a;
}
}
}
row.SetField("Total", sum);
}
I get no errors, but the Total shows the Ids of each record which is NOT what I want. (I know the Total Field is at the beginning, but this is because I have a month report to avoid scrolling just to see the total, I have added it in the front.)
Any help would be appreciated.
I have added the Totals column programmatically.
So: keep hold of these columns you have added:
List<DataColumn> myTotals = new List<DataColumn>();\
// and .Add when you create each column
Now, instead of looking at all columns:
foreach (DataColumn col in report.Columns)
just look at these 3
foreach (DataColumn col in myTotals)
If you declared them as being of type int, you can probably avoid a format/parse step, too:
sum += (int)row[col];
I have Json stored in DataBase which I deserialize into DataTable with the help of Newtonsoft.Json like this
string jsonString = "[myJsonfromDB....]";
//Deserialize to DataTable
DataTable dtSerialized = (DataTable)JsonConvert.DeserializeObject(jsonString, (typeof(DataTable)));
Which gives me result like this other columns in image are not shown
Here my label is Column and value is column value. Both of these columns will be moved to new DataTable which I'll process further for my operations. Now my problem is that I want to do it in one loop while I do it in multiple loops i.e add columns first (in first loop) and then add column values (in second loop). Currently I'm doing it like this
string colName = string.Empty;
// First Loop to add columns
foreach (DataRow dr in dtSerialized.Rows)
{
if (!string.IsNullOrEmpty(Utility.Instance.ToString(dr["label"])))
{
colName = prefix + "_" + Utility.Instance.ToString(dr["label"]).Replace(" ", string.Empty).Replace("/", "_").Replace("-", "_");
if (!dtResult.Columns.Contains(colName))
dtResult.Columns.Add(colName, typeof(string));
}
}
DataRow drSelect = dtResult.NewRow();
//Second loop to add column values
foreach (DataRow dr in dtSerialized.Rows)
{
if (!string.IsNullOrEmpty(Utility.Instance.ToString(dr["label"])))
{
colName = prefix + "_" + Utility.Instance.ToString(dr["label"]).Replace(" ", "").Replace("/", "_").Replace("-", "_");
drSelect[colName] = dr["value"];
}
}
dtResult.Rows.Add(drSelect);
dsResult.Tables.Add(dtResult);
After this I have
As much I know is that first DataRow schema is built from DataTable and then values can be added which is clear in above code. Now, How can i do it in one loop? Or should I search for alternate method which i don't know how to do this.
Thanks in advance
I am guessing I am missing something here. This looks like a transpose function and I cannot think of a way to accomplish this without two loops or transposing the data as you read it in. But going from what is posted it appears the column label holds the new DataTable’s column names. The first column is the first row of data to this new DataTable.
If this is the case then while you are looping through the rows to get the column names from column 1 (label), you can also get the “value’ from column 0 (value) and put this value in a List<string> named valuesList below.
Then after you have looped through all the rows and set the columns in the new DataTable dtResults you can add a single row from the valuesList by setting the list to a string array like below. This will produce the second picture you showed in one loop. Again I am guessing there is more to it than this simple transpose. Since a DataTable does not have a built in transpose function you will have to write your own. Not sure how you would do this in one loop though. Hope this helps.
private DataTable Transpose2ColDT(DataTable dtSource) {
string prefix = "DIAP_";
string colName = "";
DataTable dtResult = new DataTable();
List<string> valuesList = new List<String>();
if (dtSource.Rows.Count > 0) {
foreach (DataRow dr in dtSource.Rows) {
if (!dr.IsNull("Label")) {
if (dr.ItemArray[1].ToString() != "" ) {
colName = prefix + "_" + dr.ItemArray[1].ToString();
if (!dtResult.Columns.Contains(colName)) {
dtResult.Columns.Add(colName, typeof(string));
valuesList.Add(dr.ItemArray[0].ToString());
}
}
}
}
dtResult.Rows.Add(valuesList.ToArray<string>());
} // no rows in the original source
return dtResult;
}
This question already has answers here:
How to 'foreach' a column in a DataTable using C#?
(7 answers)
Closed 6 years ago.
I have a DataTable which contains column names and rows. Now as per my requirement I have to get only row value without giving the column names as I have done now.Here is the code.
data = employees.AsEnumerable().Select(row=> new List<string>
{
row.Field<string>("EmployeeName"),
row.Field<string>("Company")
})
In the above code employees is DataTable. How to do it.I have to get the row values into data variable as shown in code.
Update
data = employees.AsEnumerable().Select(row=> new List<string>
{
foreach(DataRow row in employees.Rows)
{
foreach(DataColumn col in employees.Columns)
data.Add(row[col.Ordinal].ToString());
}
})
You could simply use this syntax
data = employees.AsEnumerable().Select(row=> new List<string>
{
row[0].ToString(),
row[1].ToString()
});
Where 0 is the index of the column EmployeeName and 1 is the index of the column Company (if your query is something like SELECT EmployeeName, Company from ....)
But, in my opinion, this is really a step backwards. Using column names preserves your code from the order in which the columns are loaded from the database table.
EDIT
If you want to loop over every row and for every row on every column you could use this code (at this point there is no much sense in using IEnumerable extensions)
With foreach:
foreach(DataRow row in employees.Rows)
foreach(DataColumn col in employees.Columns)
data.Add(row[col.ColumnName].ToString());
// or
// data.Add(row[col.Ordinal].ToString());
With standard loop
for(int r = 0; r < employees.Rows.Count; r++)
for(int c = 0; c < employees.Columns.Count; c++)
data.Add(employees.Rows[r][c].ToString());
maybe you can use that?
var dt = new DataTable();
dt.AsEnumerable().Select(row => new List<string>
{
row.Field<string>(0),
row.Field<string>(1)
});
I have a datatable has data like this format
........ IVR........
.........IVR........
.........IVR........
.........City1......
.........City1......
.........City1......
.........City2......
.........City2......
.........City2......
I want to take the last row of each value. in order words, the rows that are bold now
The challenge is that i wan these three rows in a datatable. I tried to search on internet but i didn't know what is the name of this feature. could you help me please
You can GroupBy() and then select last row with the help of the Last() method.
var result = from b in myDataTable.AsEnumerable()
group b by b.Field<string>("Your_Column_Name") into g
select g.Last();
DataTable filtered = myDataTable.Clone();
foreach(DataRow row in result)
{
filtered.ImportRow(row);
}
Clone clones the structure of the DataTable, including all DataTable schemas and constraints.
This can be implemented in a simple loop using a Dictionary to hold found rows:
var cRows = new Dictionary<string, DataRow>(StringComparer.InvariantCultureIgnoreCase);
foreach (DataRow oRow in oTable.Rows)
{
var sKey = oRow["KeyValue"].ToString();
if (!cRows.ContainsKey(sKey))
{
cRows.Add(sKey, oRow);
}
else
{
cRows[sKey] = oRow;
}
}
This approach will store the last row for each unique value in the column that you nominate.
To move the selected rows into a new DataTable:
var oNewTable = oTable.Clone();
foreach (var oRow in cRows.Values)
{
oNewTable.Rows.Add(oRow);
}
Clone just clones the structure of the current table, not the rows.