ds.Tables.Add(dt);
return ds;
In the above code snippet, how can i return my dataset but exclude all blank rows i.e blank meaning rows with null or an empty string in all their columns.
You will have to do that checking before hand and then return the DataTable something like below (an example)
for (int i = dt.Rows.Count - 1; i >= 0; i--)
{
if (dt.Rows[i]["col1"] == DBNull.Value && dt.Rows[i]["col2"] == DBNull.Value)
{
dt.Rows[i].Delete();
}
}
dt.AcceptChanges();
ds.Tables.Add(dt);
return ds;
In case anyone stumbles across this article, this is the solution I came up with:
// REMOVE ALL EMPTY ROWS
dt_Parsed.Rows.Cast<DataRow>().ToList().FindAll(Row =>
{ return String.IsNullOrEmpty(String.Join("", Row.ItemArray)); }).ForEach(Row =>
{ dt_Parsed.Rows.Remove(Row); });
Here had helper function in which pass your table that you want to delete datarow with all empty columns(Here I assumed all string are of type string then it will work)
For other type u can check datacolumn type and then can make relavant checking.
public DataTable DeleteEmptyRows(DataTable dt)
{
DataTable formattedTable = dt.Copy();
List<DataRow> drList = new List<DataRow>();
foreach (DataRow dr in formattedTable.Rows)
{
int count = dr.ItemArray.Length;
int nullcounter=0;
for (int i = 0; i < dr.ItemArray.Length; i++)
{
if (dr.ItemArray[i] == null || string.IsNullOrEmpty(Convert.ToString(dr.ItemArray[i])))
{
nullcounter++;
}
}
if (nullcounter == count)
{
drList.Add(dr);
}
}
for (int i = 0; i < drList.Count; i++)
{
formattedTable.Rows.Remove(drList[i]);
}
formattedTable.AcceptChanges();
return formattedTable;
}
You can try to loop the DataTables in DataSet with this method:
public void Clear_DataTableEmptyRows(DataTable dataTableControl)
{
for (int i = dataTableControl.Rows.Count - 1; i >= 0; i--)
{
DataRow currentRow = dataTableControl.Rows[i];
foreach (var colValue in currentRow.ItemArray)
{
if (!string.IsNullOrEmpty(colValue.ToString()))
break;
dataTableControl.Rows[i].Delete();
break;
}
}
}
Related
Value
ID
A
A
A
B
B
C
Desired output
Value
ID
A
1
A
1
A
1
B
2
B
2
C
3
I need to create IDs based on grouping the value column. A single ID for all A's and then B's respectively.
Thanks in advance!
You could simply use a loop like:
for(int i = 0; i < dataTable.Rows.Count; i++){
switch(dataTable.Rows[i][0].ToString()){
case "A" :
dataTable.Rows[i][1] = 1;
break;
case "B" :
dataTable.Rows[i][1] = 2;
break;
case "C" :
dataTable.Rows[i][1] = 3;
break;
// other cases
}
}
here dt is your datatable. Use a loop like this:
int id = 1;
for (int i = 0; i < dt.Rows.Count; i++)
{
if (i == 0)
{
dt.Rows[i]["ID"] = id;
if (i != dt.Rows.Count && dt.Rows[i + 1]["Value"] != dt.Rows[i]["Value"])
{
id++;
}
}
else
{
if (dt.Rows[i - 1]["Value"] == dt.Rows[i]["Value"])
{
dt.Rows[i]["ID"] = id;
}
else
{
id = id + 1;
dt.Rows[i]["ID"] = id;
}
}
}
If the values might fall between A-Z then consider the following done in a form but can be done where ever you want.
public class Replacement
{
public string Value { get; set; }
public int Index { get; set; }
}
Form code
private void SetIdButton_Click(object sender, EventArgs e)
{
var dataTable = MockedDataTable();
var items = ReplacementData;
for (int index = 0; index < dataTable.Rows.Count; index++)
{
dataTable.Rows[index].SetField("ID",
items.FirstOrDefault(replacement =>
replacement.Value == dataTable.Rows[index].Field<string>("Value")).Index);
}
foreach (DataRow row in dataTable.Rows)
{
Console.WriteLine($"{string.Join(",", row.ItemArray)}");
}
}
private static Replacement[] ReplacementData
=> "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
.ToCharArray().Select((value, index) => new Replacement
{
Value = value.ToString(),
Index = index + 1
})
.ToArray();
private static DataTable MockedDataTable()
{
DataTable dataTable = new DataTable();
dataTable.Columns.Add("Value", typeof(string));
dataTable.Columns.Add("ID", typeof(int));
dataTable.Rows.Add("A");
dataTable.Rows.Add("A");
dataTable.Rows.Add("A");
dataTable.Rows.Add("B");
dataTable.Rows.Add("B");
dataTable.Rows.Add("C");
dataTable.Rows.Add("D");
return dataTable;
}
Output
A,1
A,1
A,1
B,2
B,2
C,3
D,4
You could also use a dictionary:
dictionary<string,int> record_dic = new dictionary<string,int>{{"A",1},{"B",2}};
I am trying to convert an array of strings to a DataGridView with little success so far. The method below is called for that purpose, but it doesn't seem to return any table.
While debugging I can see that I fetch the correct values from cont.GetAllEmployee() but when the debug goes to ConvertListToDataTable(list) the debugging does not show that method which is something unusual.
This is my current code :
private DataTable ConvertListToDataTable(List<WindowsFormsApplication1.ServiceReference1.ArrayOfString> list)
{
DataTable table = new DataTable();
List<string> columnNames = list[0];
for (int i = 0; i < columnNames.Count; i++)
{
table.Columns.Add(columnNames[i].ToString());
}
foreach (var array in list)
{
table.Rows.Add(array);
}
return table;
}
List <WindowsFormsApplication1.ServiceReference1.ArrayOfString> list = cont.GetAllEmployee();
dataGridView.DataSource = ConvertListToDataTable(list);
New rows must be instanciated by DataTable.NewRow() method to obtain new DataRow with the same scheme as DataTable.
private DataTable ConvertListToDataTable(List<WindowsFormsApplication1.ServiceReference1.ArrayOfString> list)
{
DataTable table = new DataTable();
List<string> columnNames = list[0];
for (int i = 0; i < columnNames.Count; i++)
{
table.Columns.Add(columnNames[i].ToString());
}
foreach (var array in list)
{
var NewRow = table.NewRow();
for(int i = 0; i < columnNames.Count)
{
NewRow[columnNames[i]] = array[i];
}
table.Rows.Add(NewRow);
}
return table;
}
List <WindowsFormsApplication1.ServiceReference1.ArrayOfString> list = cont.GetAllEmployee();
dataGridView.DataSource = ConvertListToDataTable(list);
dataGridView.DataBind();
In c#,i want to delete a datatable from dataset,if all the values of the datatable are zero.
How to achieve above functionality
I am using this code to add values into datatable
for (int row = startRowParcel + 1; row <= endRowParcel; row++) {
List<string> rateRow = new List<string>();
for (int col = startColumnNsa; col <= endColumnNsa; col++) {
if (Convert.ToString(ws.Cells[row, col].Value) == null)
rateRow.Add("0");
else if (Convert.ToString(ws.Cells[row, col].Value) == "1/2")
rateRow.Add("0.5");
else
rateRow.Add(Convert.ToString(ws.Cells[row, col].Value));
}
tbPriority.Rows.Add(rateRow.ToArray());
}
thanks in advance.
you can achieve this by using below code:
for(int i=0;i<dt.rows.count;i++)
{
for(intj=0;j<=dt.columns.count;j++)
{
if( dt.rows[i][j]!=0)
{
flag=1;
break;
}
}
}
if(flag==1)
{
// dont remove the table
}
else
{
ds.tables.remove(dt);
}
}
Iterate through that datatable ,check for non zero values, if all are zero remove it else not
Hope this helps..
This LINQ approach finds all tables where all rows' fields are "0":
var allZeroTables = dsPriorities.Tables.Cast<DataTable>()
.Where(tbl => tbl.AsEnumerable()
.All(r => tbl.Columns.Cast<DataColumn>()
.All(c => r.Field<string>(c) == "0")));
foreach (DataTable zeroTable in allZeroTables.ToList())
dsPriorities.Tables.Remove(zeroTable);
Enumerable.All is a short circuiting method that stops on the first non-match.
Note that the ToList() is required since you cannot modify the DataSet's DataTableCollection from within the foreach without creating a new collection.
if (!(dt.AsEnumerable().Any(x => x.Field<double>("nameOfColumn") != 0)) {
//delete data table
}
For more information see LINQ query on a DataTable
for (int row = startRowParcel + 1; row <= endRowParcel; row++) {
List<string> rateRow = new List<string>();
for (int col = startColumnNsa; col <= endColumnNsa; col++) {
if (Convert.ToString(ws.Cells[row, col].Value) == null)
rateRow.Add("0");
else if (Convert.ToString(ws.Cells[row, col].Value) == "1/2")
rateRow.Add("0.5");
else
rateRow.Add(Convert.ToString(ws.Cells[row, col].Value));
}
if (rateRow.Any(x=> x != "0"))
tbPriority.Rows.Add(rateRow.ToArray());
}
//Then you can check if tbPriority has any rows if it doesn't then remove it from the dataset
if (!tbPriority.Rows.Any())
// delete dataTable
if rateRow contains any value other than "0" the rows will get added.
I have a class in which I write several methods. I declare some objects in that class and Dispose them in a catch block. When I tried to apply Ruleset on it, it gives warning message of CA2000. My Code is as follow
public int ValidationExcelBal(string excelPath, string objectReferenceExcelPath)
{
DataTable dtPointList = new DataTable();
DataTable dtAlarm = new DataTable();
DataTable dtObjectReference = new DataTable();
try
{
int objectReferenceColNum = -1;
int objectReferenceAlarmColNum = -1;
objGGTAutoBindingToolDal.YomitoriExcelToDataTable(excelPath, ref dtPointList, ref dtAlarm);
objGGTAutoBindingToolDal.ObjectReferenceExcelToData(objectReferenceExcelPath, ref dtObjectReference);
#region code to find object reference column number in excel sheet and Alarm sheet
for (int i = 0; i < dtPointList.Columns.Count; i++)
{
for (int k = 0; k < dtPointList.Rows.Count; k++)
{
if (k < 4)
{
string name = dtPointList.Rows[k][i].ToString().Replace("\n", "").Replace(" ", "");
if (name == "ObjectReference")
{
objectReferenceColNum = i;
break;
}
}
}
}
//code to find colomn number of object reference field in Alarm sheet
for (int j = 0; j < dtAlarm.Columns.Count; j++)
{
string name = dtAlarm.Rows[0][j].ToString();
if (name.Equals("Object Reference"))
{
objectReferenceAlarmColNum = j;
break;
}
}
#endregion
if (objectReferenceColNum == -1 || objectReferenceAlarmColNum == -1)
{
return 1;
}
//if (Convert.ToString(dtObjectReference.Columns[0]).Contains("Bldg Name") || Convert.ToString(dtObjectReference.Columns[1]).Contains("Graphics Name") || Convert.ToString(dtObjectReference.Columns[2]).Contains("Controller Object Reference"))
//{
// return 2;
//}
return 3;
}
catch (Exception)
{
dtPointList.Dispose();
dtAlarm.Dispose();
dtObjectReference.Dispose();
throw;
}
}
and my warning is as follow
Warning 17 CA2000 : Microsoft.Reliability : In method 'GgtAutoBindingToolBal.ValidationExcelBal(string, string)', call System.IDisposable.Dispose on object 'dtPointList' before all references to it are out of scope. D:\Project\Pragati Installer\GGTAutoBindingBll\GgtAutoBindingToolBal.cs 26 GgtAutoBindingBll
The best thing to do is to replace the manual call to Dispose() with a using statement (will call Dispose() when running out of scope).
using (DataTable dtPointList = new DataTable()) {
...
}
Example:
using (DataTable dtPointList = new DataTable()) {
using (DataTable dtAlarm = new DataTable()) {
using (DataTable dtObjectReference = new DataTable()) {
// your code here, no need to call Dispose() on any of these objects
}
}
}
You call dispose only in the catch block. What if there is no exception in try block? Shouldn't it be disposed there as well? Try it and see if the warning meessage i still there. As it was mentioned in the other answer - using is your best option. This way the resource will be used in the scope of the using code block.
public int ValidationExcelBal(string excelPath, string objectReferenceExcelPath)
{
using (DataTable dtPointList = new DataTable())
{
using (DataTable dtAlarm = new DataTable())
{
using (DataTable dtObjectReference = new DataTable())
{
try
{
int objectReferenceColNum = -1;
int objectReferenceAlarmColNum = -1;
objGGTAutoBindingToolDal.YomitoriExcelToDataTable(excelPath, ref dtPointList, ref dtAlarm);
objGGTAutoBindingToolDal.ObjectReferenceExcelToData(objectReferenceExcelPath, ref dtObjectReference);
#region code to find object reference column number in excel sheet and Alarm sheet
for (int i = 0; i < dtPointList.Columns.Count; i++)
{
for (int k = 0; k < dtPointList.Rows.Count; k++)
{
if (k < 4)
{
string name = dtPointList.Rows[k][i].ToString().Replace("\n", "").Replace(" ", "");
if (name == "ObjectReference")
{
objectReferenceColNum = i;
break;
}
}
}
}
//code to find colomn number of object reference field in Alarm sheet
for (int j = 0; j < dtAlarm.Columns.Count; j++)
{
string name = dtAlarm.Rows[0][j].ToString();
if (name.Equals("Object Reference"))
{
objectReferenceAlarmColNum = j;
break;
}
}
#endregion
if (objectReferenceColNum == -1 || objectReferenceAlarmColNum == -1)
{
return 1;
}
//if (Convert.ToString(dtObjectReference.Columns[0]).Contains("Bldg Name") || Convert.ToString(dtObjectReference.Columns[1]).Contains("Graphics Name") || Convert.ToString(dtObjectReference.Columns[2]).Contains("Controller Object Reference"))
//{
// return 2;
//}
return 3;
}
catch (Exception)
{
dtPointList.Dispose();
dtAlarm.Dispose();
dtObjectReference.Dispose();
throw;
}
}
}
}
}
I want to do something only if selected dgvCells are in the same Column:
foreach (DataGridViewCell c in dgvC.SelectedCells)
if (c.ColumnIndex is the same) // how to say this ?
Seen no reply for sometime, here is my solution, I don't think it optimized enough, but I think it will do the job
int columnIndex = dgvC.SelectedCells[0].ColumnIndex;
bool sameCol = true;
for(int i=0;i<dgvC.SelectedCells.Count;i++)
{
if(dgvC.SelectedCells[i].ColumnIndex != columnIndex)
{
sameCol = false;
break;
}
}
if (sameCol)
{
MessageBox.Show("Same Column");
}
else
{
MessageBox.Show("Not same column");
}
EDIT:
You can also try:
int columnIndex = dgvC.SelectedCells[0].ColumnIndex;
if (dgvC.SelectedCells.Cast<DataGridViewCell>().Any(r => r.ColumnIndex != columnIndex))
{
//Not same
}
else
{
//Same
}
You can use GroupBy to make sure that cells are from the same column
if(dgvC.SelectedCells.Cast<DataGridViewCell>()
.GroupBy(c => c.ColumnIndex).Count() == 1)
{
foreach (DataGridViewCell c in dgvC.SelectedCells)
//your code
}
Something basic like this should work:
Boolean allCells = true;
int colIndex = dgvC.SelectedCells[0].ColumnIndex;
foreach (DataGridViewCell c in dgvC.SelectedCells)
{
if(c.ColumnIndex != colIndex)
{
allCells = false;
}
}
if(allCells)
{
//do stuff here
}
Try this one.
for (int i=0; i < dgvC.SelectedCells.Count; i++ )
{
int currentCellColumnIndex = dgvC.SelectedCells[i].ColumnIndex;
for (int j=i+1; j < dgvC.SelectedCells.Count-1; j++)
{
if(currentCellColumnIndex == dgvC.SelectedCells[j])
{
//Same column
//dgvC.SelectedCells[i] and all dgvC.SelectedCells[j] have same column
}
}
}