On the Foreach Loop Get Previous Value - asp.net

How can I implement the below statement using a foreach loop
for(int i = 0; i<=dt.Rows.Count -1; i++)
{
var quote = Convert.ToDouble(dt.Rows[i]["Data"]) - Convert.ToDouble(dt.Rows[i-1]["Data"])
}
when I use a foreach loop:
foreach (DataRow row in dt.Rows)
{
// how can i write this statement like the loop above.
}

You can store the previous value on each iteration of the loop to use in the next iteration.
var prev = 0;
foreach (DataRow row in dt.Rows)
{
var quote = Convert.ToDouble(row["Data"]) - Convert.ToDouble(prev);
prev = row["Data"];
}
How to set quote with an initial value of 0:
double quote = 0.0;
var prev = 0;
foreach (DataRow row in dt.Rows)
{
quote = Convert.ToDouble(row["Data"]) - Convert.ToDouble(prev);
prev = row["Data"];
}
Another way to set quote to 0 on the first iteration of the loop:
var prev = 0;
var i = 0;
foreach (DataRow row in dt.Rows)
{
double quote;
if(i == 0)
{
quote = 0.0;
}
else
{
quote = Convert.ToDouble(row["Data"]) - Convert.ToDouble(prev);
}
prev = row["Data"];
i++;
}
NOTE: this last example, based on OP's comments to my answer, is really just a stab in the dark because the OP has given no clear definition of what is needed. These add-on examples are really beyond the scope of the original question.

If you use a foreach-loop you don't have an index but only the current item. So if you want to access the previous DataRow you should use a for-loop as in your first approach. But you could write it more readable and efficient:
for(int i = 1; i < dt.Rows.Count -1; i+=2)
{
double thisData = dt.Rows[i].Field<double>("Data");
double prevData = dt.Rows[i-1].Field<double>("Data");
double quote = thisData - prevData;
}

Related

Last line of a datatable asp.net

I have a problem when I'm trying to a loop in a DataTable that a dataset contains.
I'm doing a loop like this:
for(int i = 0; i<ds.Tables[0].Rows.Count - 1 ; i++)
The problem is that I can't get the value of the last line with this one, but if I try to get rid of the "-1" and do a loop on the whole table, I'll have an out of range exception.
This out of range exception is because I have to check if the value of a line "i" is equal to the value of a line "i+1", like this:
if (ds.Tables[0].Rows[i]["Release_No"] != ds.Tables[0].Rows[i + 1]["Release_No"])
So if I do it in a loop, when the index is on the last line it will check if the last line is equal to i+1, and it's out of the table.
So I was trying to check if the index is on the last line, then just get the value of the last line, but it seems like it doesn't work.
if(ds.Tables[0].Rows.IndexOf(ds.Tables[0].Rows[i]) == ds.Tables[0].Rows.Count)
If anyone has an idea, let me know, and of course if it is not clear enough let me know, I'll give more information and more code.
Thanks for your help and your time!
Check if it's the last record, first.
I like to refactor code to read as close to sentence form as possible, explaining what you want it to do using named variables and methods, and that often gets me unlocked.
Try to make each line of code do one thing, and one thing only, like check if it is the last row:
var data = ds.Tables[0].Rows;
var lastRow = data.Count - 1;
for(int i = 0; i < lastRow ; i++)
{
if (i == lastRow){
// This is the last row. Handle the last row here.
}
else
{
// Handle all other rows here
var currentRecord = data[i];
var nextRecord = data[i + 1];
if (currentRecord["Release_No"] != nextRecord["Release_No"])
{
// Handle unique Releases...
}
}
}
Use less than or equal to like this
for(int i = 0; i<=ds.Tables[0].Rows.Count - 1 ; i++)
I hope this may get what you want.
Something like this is better ?
var lastRow = data.Count - 1;
var data = ds.Tables[0].Rows;
for(int i = 0; i< lastRow; i++)
{
testFirstCum = Convert.ToInt32(ds.Tables[0].Rows[i]["EDI_Accum_Quantity"]);
if ( i == lastRow)
{
if (DBNull.Value.Equals(data[i]))
{
quantity = 0;
}
else
{
quantity = Convert.ToInt32(data[i]);
testFirstCum = testFirstCum + quantity;
System.Diagnostics.Debug.WriteLine(quantity);
System.Diagnostics.Debug.WriteLine(testFirstCum);
}
}
else
{
var col = ds.Tables[0].Columns;
var currentRecord = data[i];
var nextRecord = data[i + 1];
if(currentRecord["Release_No"] != nextRecord["Release_No"])
{
for (int j = col[2].Ordinal; j < col.Count; j++)
{
if (DBNull.Value.Equals(data[i][j]))
{
quantity = 0;
}
else
{
quantity = Convert.ToInt32(data[i][j]);
testFirstCum = testFirstCum + quantity;
System.Diagnostics.Debug.WriteLine(quantity);
System.Diagnostics.Debug.WriteLine(testFirstCum);
}
}
}
}
}

NPOI: Excel column formatted to decimal with SXSSFWorkbook?

I am developing a website with ASP.net (VS2015 C #).
I need to export a MySql table with a large amount of data (500000+ rows and 100 columns) to excel (xlsx), with format.
After trying many options, the NPOI (v 3.20) library allows this export using types that use streaming (SXSSFWorkbook & SXSSFSheet).
If I use XSSFWorkbook I get and Out of memory filling the rows.
With SXSSFWorkbook I have been able to format the xlsx with different fonts and colors, but I am having problems with the types of data exported:
Date types ok
Int types ok
Text ok
Decimals inputs like 100.35 --> problems, I get a text column. I need a ouput like a number 100,35.
The code I use to format the data is:
SXSSFWorkbook wb = new SXSSFWorkbook();
SXSSFSheet sh = (SXSSFSheet)wb.CreateSheet("Sheet 1");
sh.SetRandomAccessWindowSize(100);
ICellStyle testStyleHeader = wb.CreateCellStyle();
ICellStyle testStyleRow = wb.CreateCellStyle();
// Header Style
testStyleHeader.FillForegroundColor = NPOI.SS.UserModel.IndexedColors.RoyalBlue.Index;
testStyleHeader.FillPattern = FillPattern.SolidForeground;
// Double style (with 2 decimals like 453.65)
ICellStyle cellStyleDouble = wb.CreateCellStyle();
cellStyleDouble.DataFormat = wb.CreateDataFormat().GetFormat("0.00");
// Font
XSSFFont hFontBlack = (XSSFFont)wb.CreateFont();
hFontBlack.FontHeightInPoints = 11;
hFontBlack.FontName = "Calibri";
hFontBlack.Color = NPOI.SS.UserModel.IndexedColors.Black.Index;
testStyleHeader.SetFont(hFontBlack);
IRow row = sh.CreateRow(0);
int j = 0;
ICell cell = row.CreateCell(j);
// Fill Header row
cell.SetCellValue("XXXX"); cell.CellStyle = testeStyleHeader; j++; cell = row.CreateCell(j);
cell.SetCellValue("YYYY"); cell.CellStyle = testeStyleHeader; j++; cell = row.CreateCell(j);
cell.SetCellValue("ZZZZ"); cell.CellStyle = testeStyleHeader; j++; cell = row.CreateCell(j);
cell.SetCellValue("WWWW"); cell.CellStyle = testeStyleHeader; j++; cell = row.CreateCell(j);
// Fill Rows
int i = 1; // row Number
IRow row2; // No Header Row
ICell cell2; // No Header cell
while (dr.Read()) // dr is the DataReader
{
row2 = sh.CreateRow(i);
for (int cont = 0; cont < NumColumns; cont++)
{
if (cont == 0) // This column is a date
{
…. // code for date format
}
else if (cont == 3) // Double column with 2 decimals¡! (values samples 100.45 5654.80 etc.)
{
ICell cell3 = row2.CreateCell(j, NPOI.SS.UserModel.CellType.Numeric);
cell3.CellStyle = cellStyleDouble;
cell3.SetCellValue(Convert.ToDouble(dr[cont]));
}
else
{…. // code for tex format, int format etc.
}
}
i++;
}
With this code, in the decimal column (cont ==3), I get a text column.
However, with the same code, if I declare the no streaming types:
XSSFWorkbook wb = new XSSFWorkbook();
XSSFSheet sh = (SSFSheet)wb.CreateSheet("Sheet 1");
Only with this changes I get a perfect numeric columnn 3...
For this line:
cellStyleDouble.DataFormat = wb.CreateDataFormat().GetFormat("0.00");
I have tried with different types:
"#.#"
"#,##0.000"
"##.#"
Etc…
In some cases I get a number, but not with the desired format.
So...streaming types do not allow this formatting?
Just change the Culture Info to en-US
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-Us");
ISheet worksheet = Workbook.CreateSheet(dt.TableName);
IRow HeaderRow = worksheet.CreateRow(0);
for (int i = 0; i < dt.Columns.Count; i++)
{
ICell HeaderCell = HeaderRow.CreateCell(i);
HeaderCell.SetCellValue(dt.Columns[i].ColumnName);
}
for (int j = 0; j < dt.Rows.Count; j++)
{
IRow Row = worksheet.CreateRow(j + 1);
for (int i = 0; i < dt.Columns.Count; i++)
{
ICell Cell = Row.CreateCell(i);
if (dt.Columns[i].DataType.IsOfType(typeof(decimal)) && dt.Rows[j][i] != DBNull.Value)
{
Cell.SetCellType(CellType.Numeric);
Cell.SetCellValue((double)dt.Rows[j][i]);
}
else
Cell.SetCellValue(dt.Rows[j][i].ToString());
}
}
Thread.CurrentThread.CurrentCulture = new CultureInfo("pt-Br");
It works for me!
can you try your formatting based on below code snippet. I am using this approach to format phone number.
XSSFCellStyle currencyCellStyle = (XSSFCellStyle)workbook.CreateCellStyle();
XSSFDataFormat currencyDataFormat = (XSSFDataFormat)workbook.CreateDataFormat();
currrencyCellStyle.SetDataFormat(currencyDataFormat.GetFormat("00000.00")); //Formats: #####.##, 00000##.##
sometimes its tricky to find exact formatting in NPOI :). Please try below approaches
ICellStyle CellStyle = workbook.CreateCellStyle();
CellStyle.DataFormat = workbook.CreateDataFormat().GetFormat("number"); // or Number
or
CellStyle cellStyle = wb.createCellStyle();
cellStyle.setDataFormat(wb.getCreationHelper().createDataFormat().getFormat("#.#")); // or #####.## or number

How to get a list of all Display Methods in a table?

I need to get a list of all display methods in a table, and I can't seem to find anything about this on the web.
Anyone know how to do this?
On display methods displayType is set to DisplayFunctionType::Get.
DictTable dt = new DictTable(tableNum(VendTable));
DictMethod dm;
DisplayFunctionType dft;
DictType dEdt;
int mtdCnt = dt.objectMethodCnt();
int i;
setPrefix(strFmt("Table: %1", dt.name()));
for (i = 1; i <= mtdCnt; i++)
{
dm = dt.objectMethodObject(i);
dft = dm.displayType();
if (dft == DisplayFunctionType::Get)
{
dEdt = new DictType(dm.returnId());
info(strFmt("Method: %1 (Label: %2)", dm.name(), dEdt.label()));
}
}

Changing Data Structure in Data Table

I want to change the structure of my DataTable. My datatable shows data in following format:-
I pivoted my datatable, using following code.
public DataTable PivotTable(DataTable source)
{
DataTable dest = new DataTable("Pivoted" + source.TableName);
dest.Columns.Add(" ");
foreach (DataRow r in source.Rows)
dest.Columns.Add(r[0].ToString());
for (int i = 0; i < source.Columns.Count - 1; i++)
{
dest.Rows.Add(dest.NewRow());
}
for (int r = 0; r < dest.Rows.Count; r++)
{
for (int c = 0; c < dest.Columns.Count; c++)
{
if (c == 0)
dest.Rows[r][0] = source.Columns[r + 1].ColumnName;
else
dest.Rows[r][c] = source.Rows[c - 1][r + 1];
}
}
dest.AcceptChanges();
return dest;
}
After pivoting my Datatable shows record in following format:-
But I need result in following format:-
That is if there are 1 Sector it should show till 1 stop, if there are 3 Sector then it should show till 3 stop. It should increase or decrease automatically.
Please help me with the code.
Thanks

Avoiding comma separator for the last value

I am generating an output on a webpage in a format like this
({"1":"Jeff","2":"Tom","3":"Michael",})
For this, basically this is the code I am using
Response.Write("(" + "{");
//
for (Int32 i = 0; i < k.Length; i++)
{
Response.Write(Convert.ToString(k.GetValue(i)) + ",");
}
//
Response.Write("}" + ")");
Notice my output, after Michael" there is a comma which I do not want since this is the last vaue but this is appearing since , is in the for loop. How to prevent this/remove this last comma from appearing?
My output should be ({"1":"Jeff","2":"Tom","3":"Michael"}) (There's no comma after last value here)
Assuming k is an array of strings
List<string> tokens = k.ToList<string>();
Response.Write("({" + String.join<string>(",", tokens) + "})");
Simplified and VB.Net, but i think you will get it:
Dim values As New List(Of String)(New String() {"1:Jeff", "2:Tom", "3:Michael"})
Dim result As String = "({" & String.Join(",", values.ToArray) & "})"
If k is a Collection like Array,List etc.
Depending on the number of iterations and how often this happens use StringBuilder instead.
StringBuilder sb = new StringBuilder();
for (Int32 i = 0; i < k.Length; i++)
{
sb.Append(",");
sb.Append(Convert.ToString(k.GetValue(i)));
}
if (sb.Length > 0) {
sb.Remove(0,1);
}
Response.Write(String.Format("({{{0}}})", sb.ToString()));
Another way is: However, it has to check every iteration.
StringBuilder sb = new StringBuilder();
for (Int32 i = 0; i < k.Length; i++)
{
if (sb.Length > 0) {
sb.Append(",");
}
sb.Append(Convert.ToString(k.GetValue(i)));
}
Response.Write(String.Format("({{{0}}})", sb.ToString()));
you can decrease your loop instead increase... like
for (Int32 i = k.Length; i > 0; i--)
and put: if (i == 1) removeComa;
Response.Write("(" + "{");
//
for (Int32 i = 0; i < k.Length; i++)
{
Response.Write(Convert.ToString(k.GetValue(i)) + (i == k.Length - 1 ? "" : ","));
}
//
Response.Write("}" + ")");
One of my favorite fixes for this is to use a prepend instead and only set comma as the seperator value after the first item (sorry for the VB):
Dim seperator As String = ""
For i As Integer = 0 To k.Length
Response.Write(seperator + Convert.ToString(k.GetValue(i)))
seperator = ","
Next
In your loop, simply use insert a "break" when the count reaches the last digit and that has been processed?
If you change how you output to write the first object in the collection then everyone after preceded by a comma it should work fine.
Response.Write("(" + "{");
//
Response.Write(Convert.ToString(k.GetValue(0)));
for (Int32 i = 1; i < k.Length; i++)
{
Response.Write("," + Convert.ToString(k.GetValue(i)));
}
//
Response.Write("}" + ")");
An alternative would be writing to a stringbuilder and outputting all but the last character

Resources