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...!!!
Related
I have grid with data being input.
Item Price Type
A 1000 1
B 1000 2
C 2000 2
D 3000 3
I want sum(price) with type that has value "2".
try
{
foreach (int i in gridView1.GetSelectedRows())
{
DataRow newRow = gridView1.GetDataRow(i);
if (newRow["NOMINAL"] is DBNull) { newRow["NOMINAL"] = 0; }
if (e.Column.FieldName == "IDISJ")
{
if (verifikasiNamaISJ(IDisj, e.RowHandle) == true)
{
TampilkanPesan.Error("Nama Item Sudah Ada!");
newRow["IDISJ"] = 0;
return;
}
newRow["IDISJ"] = IDisj;
gridView1.FocusedColumn = colNominal;
gridView1.FocusedRowHandle = e.RowHandle;
this.BeginInvoke((MethodInvoker)delegate
{
gridView1.ShowEditor();
});
cariDataItem(Convert.ToInt64(Global.PeriksaDBNullAngka(newRow["IDISJ"])));
newRow["NAMAISJ"] = NamaISJ;
newRow["NAMAJENISISJ"] = Jenis;
newRow["NOMINAL"] = 0;
}
DataTable dt = new DataTable()
>>>> txtTotalPotongan.EditValue = Convert.ToString(dt.Compute("SUM(NOMINAL)", "NAMAJENISISJ = 'Pemotongan'"));
>>>> txtTotalDiterima.EditValue = Convert.ToString(dt.Compute("SUM(NOMINAL)", "NAMAJENISISJ = 'Pendapatan'"));
}
}
catch (FbException ex)
{
TampilkanPesan.Error(ex.Message.ToString());
}
the line with >>>> was my work, but I have no idea how to do it. I guess I'm doing it wrong, since I put Datatable there. It's not data yet, still value of row.
But I don't know how to sum with filter, if not using filter I can do it. Please help me the right line of code for it.
I put this on gridview1_cellvaluechanged for every time something changes, it will update the value on textbox as well.
You could convert your datable to a list using System.Data.DataSetExtensions; and use Linq to filter and find the sum you are looking for.
var sum = dt.AsEnumerable().Where(x=> (int)x["Type"] == 2).Sum(x => (int)x["Price"]);
Here you can find a working example using your Items table.
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)
This is a C# Windows application.
I have 2 datatables in memory, I'll call them GoodTable and BadTable. The number of rows and columns are identical, so are the column names. All of the rows in BadTable have bad data in most columns. I need to loop through all rows in BadTable and replace the data in all columns with the data from the matching row in GoodTable. However there are 2 column names that I need to skip when doing the updates, I'll call them SkipColumn1 and SkipColumn2.
I've tried numerous versions of nested foreach loops with nested for loops to keep track of column count, and my results are just all over the place. If there are any database looping ninjas out there I would greatly appreciate the help.
Something like this:
var goodTable = new DataTable();
var badTable = new DataTable();
// some initialization code (add columns, fill with data)...
var columnNames = goodTable
.Columns
.Cast<DataColumn>()
.Where(column => column.ColumnName != "SkipColumn1" && column.ColumnName != "SkipColumn2")
.Select(column => column.ColumnName)
.ToArray();
for (var i = 0; i < goodTable.Rows.Count; i++)
{
foreach (var columnName in columnNames)
{
badTable.Rows[i][columnName] = goodTable.Rows[i][columnName];
}
}
This is the answer I'm accepting because it's the cleanest and most simple in my opinion.
for (var i = 0; i < GoodDT.Rows.Count; i++)
{
for (var x = 0; x < GoodDT.Columns.Count; x++)
{
if (BadDT.Columns[x].ColumnName != "skip1" && BadDT.Columns[x].ColumnName != "skip2")
{
BadDT.Rows[i][x] = GoodDT.Rows[i][x];
}
}
}
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());
}
Let suppose there are three columns in my DataTable
code
name
color
If I know the code and name, how can I update the color of that specific row whose code and name match my criteria? I want to do this without using Loops!
You can use LINQ:
DataRow dr = datatable.AsEnumerable().Where(r => ((string)r["code"]).Equals(someCode) && ((string)r["name"]).Equals(someName)).First();
dr["color"] = someColor;
Of course I'm assuming all those criteria are strings. You should change the casts to the correct types.
// Use the Select method to find all rows matching the name and code.
DataRow[] rows = myDataTable.Select("name 'nameValue' AND code = 'codeValue');
for(int i = 0; i < rows.Length; i ++)
{
rows[i]["color"] = colorValue;
}
DataTable recTable = new DataTable();
// do stuff to populate table
recTable.Select(string.Format("[code] = '{0}' and [name] = '{1}'", someCode, someName)).ToList<DataRow>().ForEach(r => r["Color"] = colorValue);
With LINQ:
var dataRows = dt.AsEnumerable().Select(c => { c["color"] = c["Code"].ToString() == "1" ? "Red" : "White"; return c; });
dt = dataRows.CopyToDataTable();
You could do:
foreach (DataRow row in datatable.Rows)
{
if(row["code"].ToString() == someCode && row["name"].ToString() == someName)
{
row["color"] = someColor;
}
}