I want to split DataTable so that I can upload its chunks from one place to other.
For example
pick first 100 rows.
pick next 100 rows.
pick next 100 rows and so on ...
Is there any way to do it just like cursor in Database? I do not like to use loops etc. for counting rows.
YourDataTable.Select() gives you an array of Data
What about linq?
Fro example YourDataTable.Select (x => x).Take (100).ToEnumerable() gives you the first 100 DataRows and YourDataTable.Select (x => x).Skip(100).Take (100).ToEnumerable() for the next 100.
Try this:
public static class DataExtensions
{
public static IEnumerable<IEnumerable<DataRow>> Partition(this DataTable dataTable, int partitionSize)
{
var numRows = Math.Ceiling((double)dataTable.Rows.Count);
for(var i = 0; i < numRows / partitionSize; i++)
{
yield return Partition(dataTable, i * partitionSize, i * partitionSize + partitionSize);
}
}
private static IEnumerable<DataRow> Partition(DataTable dataTable, int index, int endIndex)
{
for(var i = index; i < endIndex && i < dataTable.Rows.Count; i++)
{
yield return dataTable.Rows[i];
}
}
}
var partitions = dataTable.Partition(100);
Doing:
dataTable.Skip(0).Take(100);
dataTable.Skip(100).Take(100);
dataTable.Skip(200).Take(100);
dataTable.Skip(300).Take(100);
Will iterate 0 times, and take 100 on the first execution. Then iterate through 100 rows, take 100, then iterate 200 rows, then take 100, etc.
The above will do a lazy fetch and only hit each row once
This is a simply way to do that:
public DataSet test(DataSet ds, int max)
{
int i = 0;
int j = 1;
DataSet newDs = new DataSet();
DataTable newDt = ds.Tables[0].Clone();
newDt.TableName = "Table_" + j;
newDt.Clear();
foreach (DataRow row in ds.Tables[0].Rows)
{
DataRow newRow = newDt.NewRow();
newRow.ItemArray = row.ItemArray;
newDt.Rows.Add(newRow);
i++;
if (i == max)
{
newDs.Tables.Add(newDt);
j++;
newDt = ds.Tables[0].Clone();
newDt.TableName = "Table_" + j;
newDt.Clear();
i = 0;
}
}
return newDs;
}
Can you try?
Use linq select part of record
this link in stack overflow can be helpful
Split a collection into n parts with LINQ?
Check: splitting a large datatable into smaller batches from c-sharpcorner.com
internal static List<datatable> SplitTable(DataTable originalTable, int batchSize)
{
List<datatable> tables = new List<datatable>();
DataTable new_table = new DataTable();
new_table = originalTable.Clone();
int j = 0;
int k = 0;
if (originalTable.Rows.Count <= batchSize)
{
new_table.TableName = "Table_" + k;
new_table = originalTable.Copy();
tables.Add(new_table.Copy());
}
else
{
for (int i = 0; i < originalTable.Rows.Count; i++)
{
new_table.NewRow();
new_table.ImportRow(originalTable.Rows[i]);
if ((i + 1) == originalTable.Rows.Count)
{
new_table.TableName = "Table_" + k;
tables.Add(new_table.Copy());
new_table.Rows.Clear();
k++;
}
else if (++j == batchSize)
{
new_table.TableName = "Table_" + k;
tables.Add(new_table.Copy());
new_table.Rows.Clear();
k++;
j = 0;
}
}
}
return tables;
}
Improving on #vanessa
public DataSet SplitDataTable(DataTable tableData, int max)
{
int i = 0;
int j = 1;
int countOfRows = tableData.Rows.Count;
DataSet newDs = new DataSet();
DataTable newDt = tableData.Clone();
newDt.TableName = tableData.TableName+"_" + j;
newDt.Clear();
foreach (DataRow row in tableData.Rows)
{
DataRow newRow = newDt.NewRow();
newRow.ItemArray = row.ItemArray;
newDt.Rows.Add(newRow);
i++;
countOfRows--;
if (i == max )
{
newDs.Tables.Add(newDt);
j++;
newDt = tableData.Clone();
newDt.TableName = tableData.TableName + "_" + j;
newDt.Clear();
i = 0;
}
if (countOfRows == 0 && i < max)
{
newDs.Tables.Add(newDt);
j++;
newDt = tableData.Clone();
newDt.TableName = tableData.TableName + "_" + j;
newDt.Clear();
i = 0;
}
}
return newDs;
}
Related
I have just started working with EPPlus. i have data table which has some numeric data and formula. when i load data table by EPPlus and save to excel then formula not evaluated i found when i open the same excel file. formula lies in excel cell as string like SUM(A3:B3)
To evaluate formulate i have tried many options of EPPLUS and those are listed here
pack.Workbook.Worksheets["Test"].Calculate();
pack.Workbook.Worksheets["Test"].Cells["A3"].Calculate();
pack.Workbook.Worksheets["Test"].Cells["B3"].Calculate();
ws.Calculate();
Here i am referring my full sample code where formula not working. please have a look and tell me what i need to add in my code to evaluate formula.
private void button1_Click(object sender, EventArgs e)
{
DataTable dt = GetDataTable();
string path = #"d:\EPPLUS_DT_Excel.xlsx";
Stream stream = File.Create(path);
using (ExcelPackage pack = new ExcelPackage())
{
ExcelWorksheet ws = pack.Workbook.Worksheets.Add("Test");
ws.Cells["A1"].LoadFromDataTable(dt, false);
//pack.Workbook.Worksheets["Test"].Calculate();
//pack.Workbook.Worksheets["Test"].Cells["A3"].Calculate();
//pack.Workbook.Worksheets["Test"].Cells["B3"].Calculate();
ws.Calculate();
pack.SaveAs(stream);
stream.Close();
MessageBox.Show("Done");
}
}
public DataTable GetDataTable()
{
string strSum = "", strColName, strImmediateOneUp = "", strImmediateTwoUp = "";
int startsum = 0;
int currow = 0;
bool firstTimeSum = true;
int NumRows = 3;
int NumColumns = 2;
DataTable dt = new DataTable();
for (int col = 0; col < NumColumns; col++)
{
strColName = GenerateColumnText(col);
DataColumn datacol = new DataColumn(strColName, typeof(object));
dt.Columns.Add(datacol);
}
for (int row = 0; row < NumRows; row++)
{
dt.Rows.Add();
for (int col = 0; col < NumColumns; col++)
{
if (row < 2)
{
dt.Rows[row][col] = Convert.ToInt32(new Random().Next(1, NumRows));
}
else
{
if (firstTimeSum)
{
if (row - currow == 2)
{
currow = row;
startsum = 0;
firstTimeSum = false;
}
else
{
startsum = 1;
}
}
else
{
if (row - currow == 3)
{
currow = row;
startsum = 0;
}
}
if (startsum == 0)
{
strColName = GenerateColumnText(col);
strImmediateOneUp = strColName + ((row + 1) - 1).ToString();
strImmediateTwoUp = strColName + ((row + 1) - 2).ToString();
strSum = string.Format("+SUM({0}:{1})", strImmediateTwoUp, strImmediateOneUp);
dt.Rows[row][col] = strSum;
}
else
{
dt.Rows[row][col] = Convert.ToInt32(new Random().Next(1, NumRows));
}
}
}
startsum = 1;
}
return dt;
}
private string GenerateColumnText(int num)
{
string str = "";
char achar;
int mod;
while (true)
{
mod = (num % 26) + 65;
num = (int)(num / 26);
achar = (char)mod;
str = achar + str;
if (num > 0) num--;
else if (num == 0) break;
}
return str;
}
When adding a formula to a cell you use the Formula property. When you load a range from a DataTable using LoadFromDataTable it has no way of knowing that some of the values are meant to be interpreted as formulas.
You can use LoadDataTable to populate the cells on which the formulas will operate, but for the formulas you'll need to set the Formula property.
I have populated my data table with random values and formula like =SUM(A1:A2)
when there is 150 columns and 4000 rows in datatable then ReoGrid taking approx 20 minute to be populated.
when i am populating ReoGrid without formula then it takes few second to populate ReoGrid but the moment many SUM formulas are being assigned to cell dynamically then ReoGrid take long time to populated.
Here i am sharing my code. so my request please guys see my code logic and tell me is there any flaw when assigning formula to many cell of ReoGrid.
please tell me how could i simplify the logic to populate grid with formula. Is there way to increase the performance of my code with formula as a result ReoGrid can be populated with in few sec or few minute.
Looking for suggestion and guide line. ReoGrid is free component for winform application https://reogrid.net/.
Here is my code
private void btnBindTable_Click(object sender, EventArgs e)
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
string strSum = "", strColName, strImmediateOneUp = "", strImmediateTwoUp = "";
int startsum = 0;
int currow = 0;
bool firstTimeSum = true;
int NumRows = 4000;
int NumColumns = 150;
var sheet = reoGrd.CurrentWorksheet;
sheet.Resize(NumRows, NumColumns); // resize
DataTable dt = new DataTable();
for (int col = 0; col < NumColumns; col++)
{
strColName = GenerateColumnText(col);
DataColumn datacol = new DataColumn(strColName, typeof(string));
dt.Columns.Add(datacol);
}
for (int row = 0; row < NumRows; row++)
{
dt.Rows.Add();
for (int col = 0; col < NumColumns; col++)
{
if (row < 2)
{
dt.Rows[row][col] = new Random().Next(1, NumRows).ToString("D2");
}
else
{
if (firstTimeSum)
{
if (row - currow == 2)
{
currow = row;
startsum = 0;
firstTimeSum = false;
}
else
{
startsum = 1;
}
}
else
{
if (row - currow == 3)
{
currow = row;
startsum = 0;
}
}
if (startsum == 0)
{
strColName = GenerateColumnText(col);
strImmediateOneUp = strColName + ((row + 1) - 1).ToString();
strImmediateTwoUp = strColName + ((row + 1) - 2).ToString();
dt.Rows[row][col] = strSum;
string cellname = GenerateColumnText(col) + (row + 1).ToString();
var cell = sheet.Cells[cellname];
cell.Style.BackColor = Color.LightGoldenrodYellow;
}
else
{
dt.Rows[row][col] = new Random().Next(1, NumRows).ToString("D2");
}
}
}
startsum = 1;
}
sheet["A1"] = dt;
stopwatch.Stop();
TimeSpan timeSpan = stopwatch.Elapsed;
MessageBox.Show(string.Format("Time elapsed: {0}h {1}m {2}s {3}ms", timeSpan.Hours, timeSpan.Minutes, timeSpan.Seconds, timeSpan.Milliseconds));
}
string[] SName = Request.Form.GetValues("Description");
string[] Email = Request.Form.GetValues("Email");
DataTable dtable = dt();
for (int i = 0; i <= SName.Length - 1; i++)
{
DataRow row1 = dtable.NewRow();
row1["Description"] = SName[i];
row1["Email"] = Email[i];
DAL.DMSS insertdata = new DMSS();
insertdata.INSERT_DATA(loggeduser.SUBSIDIARY_CD, input, SName[i], Email[i]);
}
above are my code to get the data from dynamic row add.
if i have 2 rows,data i get is :
now i want to add 1 more data ,sequence number
tried this code but not working..
for (int i = 0; i <= SName.Length - 1; i++)
{
if (i.length <2 )
{
string strvalue = i.PadLeft(2, '0');
}
else
{
string strvalue = i;
}
DataRow row1 = dtable.NewRow();
row1["Description"] = SName[i];
row1["Email"] = Email[i];
DAL.DMSS insertdata = new DMSS();
insertdata.INSERT_DATA(loggeduser.SUBSIDIARY_CD, input, SName[i], Email[i], strvalue);
}
for (int i = 0; i <= SName.Length - 1; i++)
{
var rowNumber = (i + 1).ToString("0#");
}
The problem is that I need to insert data into Excel from the collection several times using a single template for the entire collection.
using (var pckg = new ExcelPackage(new FileInfo(association.TemplatePath)))
{
var workSheet = pckg.Workbook.Worksheets[1];
var dataTable = WorksheetToDataTable(workSheet);
/*Some stuff*/
FindAndReplaceValue(workSheet, dictionary, row);
}
private DataTable WorksheetToDataTable(ExcelWorksheet oSheet)
{
int totalRows = oSheet.Dimension.End.Row;
int totalCols = oSheet.Dimension.End.Column;
DataTable dt = new DataTable(oSheet.Name);
DataRow dr = null;
for (int i = 1; i <= totalRows; i++)
{
if (i > 1) dr = dt.Rows.Add();
for (int j = 1; j <= totalCols; j++)
{
if (i == 1)
dt.Columns.Add((oSheet.Cells[i, j].Value ?? "").ToString());
else
dr[j - 1] = (oSheet.Cells[i, j].Value ?? "").ToString();
}
}
return dt;
}
First picture - My template. Second - First element of collection (with data, style, merging). Third - Other elements has only data
I just made copies of rows
for (int i = 0; i < invoiceList.Count; i++)
{
workSheet.Cells[1, 1, totalRows, totalCols].Copy(workSheet.Cells[i * totalRows + 1, 1]);
}
If you want to copy range just use :
workSheet.Cells["A1:I1"].Copy(workSheet.Cells["A4:I4"]);
I have a data in data table with say 4 columns.Out of those 10 columns first column contains the date.The data in the table is in the form :
I/p
"15/12/2010",username,24,No
"16/12/2010",username,24,No
"17/12/2010",username,24,No
"18/12/2010",username,24,No
"19/12/2010",username,24,No
"20/12/2010",username,25,No
"21/12/2010",username,24,yes
"22/12/2010",username,24,No
"23/12/2010",username,24,No
"24/12/2010",username,24,No
"25/12/2010",username,24,No
"26/12/2010",Prakhar,24,No
"27/12/2010",username,24,No
"28/12/2010",username,24,No
We have to bind the o/p with the repeater.
For aforemenioned i/p the output should be :
O/P
"15/12/2010 - 20/12/2010",username,24,No
"21/12/2010 - 21/12/2010",username,24,Yes
"22/12/2010 - 25/12/2010",username,24,no
"26/12/2010 - 26/12/2010",username,24,no
"27/12/2010 - 28/12/2010",username,24,no
I.e. we are clubbing all the dates whose corresponsing column values are matching.
We have to write a c# code for it.
First I have created a new Datatable for our final result:
DataTable dtInventoryTable = new dtInventoryTable();
dtInventoryTable.Columns.Add("RateDate", typeof(string));
dtInventoryTable.Columns.Add("RatePlanId", typeof(string));
dtInventoryTable.Columns.Add("RoomTypeId", typeof(string));
private DataTable DisplayInventoryDetails(DataTable dtInventoryDetail)
{
for (int i = 0; i < dtInventoryDetail.Rows.Count; i++)
{
String[] row = new String[dtInventoryDetail.Columns.Count];
String[] row1 = new String[dtInventoryDetail.Columns.Count];
string str=string.Empty;
int h=0;
str = dtInventoryDetail.Rows[i][0].ToString() + " - " +dtInventoryDetail.Rows[i]0].ToString();
for (int j = i+1;j< dtInventoryDetail.Rows.Count; j++)
{
for (int x = 1; x < dtInventoryDetail.Columns.Count; x++)
{
row[x] = dtInventoryDetail.Rows[i][x].ToString();
}
for (int y = 1; y < dtInventoryDetail.Columns.Count; y++)
{
row1[y] = dtInventoryDetail.Rows[j][y].ToString();
}
bool result = ArraysEqual(row, row1);
if (!result)
{
dtInventoryTable = GetRoomRateTable(row, str);
i = j-1;
h = j;
break;
}
else
str= dtInventoryDetail.Rows[i][0].ToString() + " - " + dtInventoryDetail.Rows[j][0].ToString();
h = j;
}
}
if (h >= dtInventoryDetail.Rows.Count-1)
{
dtInventoryTable = GetRoomRateTable(row, str);
break;
}
}
return dtInventoryTable;
}
private DataTable GetRoomRateTable(String[] row,string str)
{
row[0] = str;
dtInventoryTable.LoadDataRow(row, true);
return dtInventoryTable;
}