C# How to improve loop populating Excel cells - c#

I'm mainly parsing large amounts of text from a text file and then populating it into an excel.
//populate into worksheet
for (int x = 0; x < rawLine.Length; x++)
{
string[] tempLine = rawLine[x].Split(';');
for (int y = 0; y < tempLine.Length; y++)
{
DateTime hour = Convert.ToDateTime(tempLine[6]);
xlWorkSheet.Cells[y + 2, 1] = tempLine[0];
xlWorkSheet.Cells[y + 2, 2] = tempLine[1];
xlWorkSheet.Cells[y + 2, 3] = tempLine[2];
xlWorkSheet.Cells[y + 2, 4] = tempLine[3];
xlWorkSheet.Cells[y + 2, 5] = tempLine[4];
xlWorkSheet.Cells[y + 2, 6] = tempLine[5];
xlWorkSheet.Cells[y + 2, 7] = tempLine[6];
xlWorkSheet.Cells[y + 2, 8] = tempLine[7];
xlWorkSheet.Cells[y + 2, 9] = tempLine[8];
xlWorkSheet.Cells[y + 2, 10] = tempLine[9];
xlWorkSheet.Cells[y + 2, 11] = tempLine[10];
xlWorkSheet.Cells[y + 2, 12] = hour.Hour;
xlWorkSheet.Cells[y + 2, 13] = tempLine[8] == "0" ? "SAME" : tempLine[9];
}
Console.WriteLine("Current line = " + x + "\n");
}
Currently this code works, but it's just taking way too long. Is there anyway to speed it up? I have done some searching but found nothing much specific.
Thanks in advance.

It will probably be a very small improvement, but this line:
DateTime hour = Convert.ToDateTime(tempLine[6]);
Should be moved outside the y loop because it doesn't depend on it.
Other than that, you should probably look into some way to set multiple cells at the same time--most of the time is probably spent doing round trips to Excel. (It looks like this is what #Gusman suggests in the comments).
#Mohit's answer is good too because it is much shorter and simpler.

You can try:
//populate into worksheet
DateTime hour;
string[] tempLine;
StringBuilder output = new StringBuilder();
for (int x = 0; x < rawLine.Length; x++)
{
tempLine = rawLine[x].Split(';');
for (int y = 0; y < tempLine.Length; y++)
{
hour = Convert.ToDateTime(tempLine[6]);
xlWorkSheet.Cells[y + 2, 1] = tempLine[0];
xlWorkSheet.Cells[y + 2, 2] = tempLine[1];
xlWorkSheet.Cells[y + 2, 3] = tempLine[2];
xlWorkSheet.Cells[y + 2, 4] = tempLine[3];
xlWorkSheet.Cells[y + 2, 5] = tempLine[4];
xlWorkSheet.Cells[y + 2, 6] = tempLine[5];
xlWorkSheet.Cells[y + 2, 7] = tempLine[6];
xlWorkSheet.Cells[y + 2, 8] = tempLine[7];
xlWorkSheet.Cells[y + 2, 9] = tempLine[8];
xlWorkSheet.Cells[y + 2, 10] = tempLine[9];
xlWorkSheet.Cells[y + 2, 11] = tempLine[10];
xlWorkSheet.Cells[y + 2, 12] = hour.Hour;
xlWorkSheet.Cells[y + 2, 13] = tempLine[8] == "0" ? "SAME" : tempLine[9];
}
output.AppendLine("Current line = " + x);
}
Console.WriteLine(output.ToString());

May be just to improve the loop you can write like this. This does not improve the performance but would look cleaner.
for (int x = 0; x < rawLine.Length; x++)
{
string[] tempLine = rawLine[x].Split(';');
for (int y = 0; y < tempLine.Length; y++)
{
DateTime hour = Convert.ToDateTime(tempLine[6]);
for(int z=0; z<11; z++)
{
xlWorkSheet.Cells[y + 2, (z+1)] = tempLine[z];
}
xlWorkSheet.Cells[y + 2, 12] = hour.Hour;
xlWorkSheet.Cells[y + 2, 13] = tempLine[8] == "0" ? "SAME" : tempLine[9];
}
Console.WriteLine("Current line = " + x + "\n");
}

Related

How to Display a Jagged Array? - C#

I am trying to get a jagged array that will solve the sums of the elements from dailyTemperature and that will successfully display them in the Main () under the Weather class. This is what I have so far.
public int[,] GetTemperatures()
{
int[,] dailyTemperature =
{
{38, 40, 42, 34},
{55, 41, 40, 30},
{28, 39, 21, 60},
{61, 52, 43, 42},
{35, 36, 30, 29},
{24, 33, 37, 40}
};
Console.Write(" ");
for (int i = 0; i < dailyTemperature.Length; i++)
{
Console.Write(dailyTemperature[i] + " ");
}
Console.WriteLine();
for (int i = 0; i < dailyTemperature.GetLength(0); i++)
{
Console.Write(dailyTemperature[i].Substring(0, dailyTemperature[i].Length - 1) + " ");
for (int j = 0; j < dailyTemperature.GetLength(1); j++)
{
Console.Write(dailyTemperature[i, j] + " ");
}
Console.WriteLine();
}
return dailyTemperature;
}
{
public int[] GetTemperatureSum(int [,] dailyTemperature)
{
int[][] temperatureSum= new int[6][];
temperatureSum[0][1] = dailyTemperature[0, 0] + dailyTemperature[0, 1] + dailyTemperature[0, 2] + dailyTemperature[0, 3];
temperatureSum[0][2] = dailyTemperature[1, 0] + dailyTemperature[1, 1] + dailyTemperature[1, 2] + dailyTemperature[1, 3];
temperatureSum[0][3] = dailyTemperature[2, 0] + dailyTemperature[2, 1] + dailyTemperature[2, 2] + dailyTemperature[2, 3];
temperatureSum[0][4] = dailyTemperature[3, 0] + dailyTemperature[3, 1] + dailyTemperature[3, 2] + dailyTemperature[3, 3];
temperatureSum[0][5] = dailyTemperature[4, 0] + dailyTemperature[4, 1] + dailyTemperature[4, 2] + dailyTemperature[4, 3];
temperatureSum[0][6] = dailyTemperature[5, 0] +dailyTemperature[5, 1] + dailyTemperature[5, 2] + dailyTemperature[5, 3];
for (int i = 0; i < temperatureSum.GetLength(0); i++)
{
for (int j=0; j<temperatureSum.GetLength(1); j++)
{
Console.Write(temperatureSum[i][j]);
}
Console.WriteLine();
}
return temperatureSum;
}
static void Main(string[] args)
{
Weather weather= new Weather();
{
weather.GetTemperatures();
weather.GetTemperatureSum(dailyTemperature);
}
};
My strategy here is to display all of these methods through the Main() method, however I am getting an error under (dailyTemperature) by weather.GetTemperatureSum. This is what the error says, "An object reference is required for the nonstatic field, method, or property 'member'".
I'd love it if someone could help me on this, although as I understand the formatting has to be relatively similar to this. I absolutely need to, for example, solve the sums through the computer as opposed to doing so manually. Thanks.
More details about:
Multidimensional Arrays
Jagged Arrays
Multidimensional Array [][] vs [,] [duplicate]
int[,] dailyTemperatures =
{
{ 38, 40, 42, 34 },
{ 55, 41, 40, 30 },
{ 28, 39, 21, 60 },
{ 61, 52, 43, 42 },
{ 35, 36, 30, 29 },
{ 24, 33, 37, 40 }
};
Weather.GetTemperatures(dailyTemperatures);
Weather.GetTemperatureSum(dailyTemperatures);
public static class Weather
{
public static int[,] GetTemperatures(int[,] dailyTemperatures)
{
var rows = dailyTemperatures.GetUpperBound(0) + 1;
var columns = dailyTemperatures.Length / rows;
for (var i = 0; i < rows; i++)
{
for (var j = 0; j < columns; j++)
{
Console.Write($"{dailyTemperatures[i, j]} \t");
}
Console.WriteLine();
}
return dailyTemperatures;
}
public static int[] GetTemperatureSum(int[,] dailyTemperature)
{
var temperatureSum = new int[6];
temperatureSum[0] = dailyTemperature[0, 0] + dailyTemperature[0, 1] + dailyTemperature[0, 2] + dailyTemperature[0, 3];
temperatureSum[1] = dailyTemperature[1, 0] + dailyTemperature[1, 1] + dailyTemperature[1, 2] + dailyTemperature[1, 3];
temperatureSum[2] = dailyTemperature[2, 0] + dailyTemperature[2, 1] + dailyTemperature[2, 2] + dailyTemperature[2, 3];
temperatureSum[3] = dailyTemperature[3, 0] + dailyTemperature[3, 1] + dailyTemperature[3, 2] + dailyTemperature[3, 3];
temperatureSum[4] = dailyTemperature[4, 0] + dailyTemperature[4, 1] + dailyTemperature[4, 2] + dailyTemperature[4, 3];
temperatureSum[5] = dailyTemperature[5, 0] + dailyTemperature[5, 1] + dailyTemperature[5, 2] + dailyTemperature[5, 3];
for (var i = 0; i < temperatureSum.GetLength(0); i++)
{
Console.WriteLine(temperatureSum[i]);
}
return temperatureSum;
}
}
In the GetTemperatureSum method, the returned type is an array (int[]).
It is better to pass dailyTemperatures variable as a method parameter

C# Dividing a Matrix into Sub Blocks

i have a matrix came from an image 1600x1600. now i need to assign this matrix into 4x4 blocks. As an example:
00 01 02 03
IMAGE = 04 05 06 07 BLOCK(i) = 00 01 BLOCK(i+1) = 02 03
08 09 0A 0B 04 05 06 07
0C 0D 0E 0F
BLOCK(i+2) = 08 09 BLOCK(i+3) = 0A 0B
0C 0D = 0E 0F
1 ) Firstly i dont know the image dimensions , the user opens it. i get it later. my test image 1600x1600.But blocks dimensions are fixed at 4x4. And image dimensions are , lets we agree can be divided with 4 for now...
2 ) I dont know how many blocks going to be.
3 ) I need to acces the row and coloumb of the blocks later because i will be performing mathematical operations with the blocks later... For example , XOR operation with block(n)[x,y] with block(n+1) [x,y].
So this decleration part , this part of the program is very very important.
i stucked this part of the program for 2 weeks i cant continue. Pls help me. İt looks very simple code but.......
My structure is like this , begining part
private void Form1_Load(object sender, EventArgs e)
{
Bitmap bmp = new Bitmap("c:\\yavanna.jpg");
pictureBox1.Image = Image.FromFile("c:\\yavanna.jpg");
int width = bmp.Width;
int height = bmp.Height;
Color p;
int[,] alpha_map_int = new int[width, height];
int[,] red_map_int = new int[width, height];
int[,] green_map_int = new int[width, height];
int[,] blue_map_int = new int[width, height];
int[,] grayscale_map_int = new int[width, height];
string[,] gray_scale_map = new string[width, height];
string temp_hexValue;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
//get pixel value
p = bmp.GetPixel(x, y);
//extract pixel component ARGB
int a = p.A;
alpha_map_int[x, y] = a;
int r = p.R;
red_map_int[x, y] = r;
int g = p.G;
green_map_int[x, y] = g;
int b = p.B;
blue_map_int[x, y] = b;
//convert to gryscale
double grayscale = 0.2126 * red_map_int[x,y] + 0.7152 * green_map_int[x, y] + 0.0722 * blue_map_int[x, y];
grayscale_map_int[x, y] = Convert.ToInt32(grayscale);
temp_hexValue = Convert.ToString(grayscale_map_int[x, y]);
gray_scale_map[x, y] = temp_hexValue;
}
}
Here's a version of jdweng's answer, that generates 4x4 arrays and handles source arrays that don't divide by 4. You can see why he posted a simplified sample. Any bigger and it would be worth using two more loops to populate the 4x4 array.
'image' is the input, 'bytes4x4' is the output.
List<List<List<byte>>> bytes4x4 = new List<List<List<byte>>>();
for (int row = 0; row<length-3 ; row += 4)
{
for (int col = 0; col<width-3; col += 4)
{
bytes4x4.Add(new List<List<byte>>() {
new List<byte>() { image[row, col], image[row, col + 1], image[row, col + 2], image[row, col + 3]},
new List<byte>() { image[row + 1, col], image[row + 1, col + 1], image[row + 1, col + 2], image[row + 1, col + 3] },
new List<byte>() { image[row + 2, col], image[row + 2, col + 1], image[row + 2, col + 2], image[row + 2, col + 3] },
new List<byte>() { image[row + 3, col], image[row + 3, col + 1], image[row + 3, col + 2], image[row + 3, col + 3] }
});
}
This declares and populates 'bytes4x4', which is a long list of two dimensional blocks. Access a block like this:
var block100 = bytes4x4[100];
And use that to get a pixel:
var block100pixelrow1col3 = block100[1][3];
or
var block100pixelrow1col3 = bytes4x4[100][1][3];
Note that these indexs are all zero based, so there's no element [4] in the blocks.
Now I think about it, you might be after a 2-dimensional array of 2-dimensional blocks. If so the code would look like this:
var bytes4x4 = new List<List<List<List<byte>>>>();
for (int row = 0; row<length-3 ; row += 4)
{
var row = new List<List<List<byte>>>();
bytes4x4.Add(row);
for (int col = 0; col<width-3; col += 4)
{
row.Add(new List<List<byte>>() {
new List<byte>() { image[row, col], image[row, col + 1], image[row, col + 2], image[row, col + 3]},
new List<byte>() { image[row + 1, col], image[row + 1, col + 1], image[row + 1, col + 2], image[row + 1, col + 3] },
new List<byte>() { image[row + 2, col], image[row + 2, col + 1], image[row + 2, col + 2], image[row + 2, col + 3] },
new List<byte>() { image[row + 3, col], image[row + 3, col + 1], image[row + 3, col + 2], image[row + 3, col + 3] }
});
}
Then you could access a block that is 14 rows down and 23 columns across like this:
var block14by23 = bytes4x4[14][23];
Try following :
const string FILENAME = #"c:\temp\test.jpg";
public Form1()
{
InitializeComponent();
Bitmap image = new Bitmap(FILENAME);
int height = (int)image.Height ;
int width = (int)image.Width;
List<List<List<Color>>> bytes = new List<List<List<Color>>>();
List<List<List<Int32>>> grayscale_map_int = new List<List<List<Int32>>>();
for (int row = 0; row < height; row += 4)
{
for (int col = 0; col < width; col += 4)
{
bytes.Add(new List<List<Color>>() {
new List<Color>() { image.GetPixel(col, row), image.GetPixel(col + 1, row), image.GetPixel(col + 2, row), image.GetPixel(col + 3, row)} ,
new List<Color>() { image.GetPixel(col, row + 1), image.GetPixel(col + 1, row + 1), image.GetPixel(col + 2, row + 1), image.GetPixel(col + 3, row + 1)} ,
new List<Color>() { image.GetPixel(col, row + 2), image.GetPixel(col + 1, row + 2), image.GetPixel(col + 2, row + 2), image.GetPixel(col + 3, row + 2)} ,
new List<Color>() { image.GetPixel(col, row + 3), image.GetPixel(col + 1, row + 3), image.GetPixel(col + 2, row + 3), image.GetPixel(col + 3, row + 3)} ,
});
grayscale_map_int.Add(new List<List<Int32>>() {
new List<Int32>() { GetGrayScale(image.GetPixel(col, row)), GetGrayScale(image.GetPixel(col + 1, row)), GetGrayScale(image.GetPixel(col + 2, row)), GetGrayScale(image.GetPixel(col + 3, row))} ,
new List<Int32>() { GetGrayScale(image.GetPixel(col, row + 1)), GetGrayScale(image.GetPixel(col + 1, row + 1)), GetGrayScale(image.GetPixel(col + 2, row + 1)), GetGrayScale(image.GetPixel(col + 3, row + 1))} ,
new List<Int32>() { GetGrayScale(image.GetPixel(col, row + 2)), GetGrayScale(image.GetPixel(col + 1, row + 2)), GetGrayScale(image.GetPixel(col + 2, row + 2)), GetGrayScale(image.GetPixel(col + 3, row + 2))} ,
new List<Int32>() { GetGrayScale(image.GetPixel(col, row + 3)), GetGrayScale(image.GetPixel(col + 1, row + 3)), GetGrayScale(image.GetPixel(col + 2, row + 3)), GetGrayScale(image.GetPixel(col + 3, row + 3))} ,
});
}
}
}
public Int32 GetGrayScale(Color color)
{
return Convert.ToInt32(0.2126 * color.R + 0.7152 * color.G + 0.0722 * color.B);
}

Highlighting cells/making them bold in Excel

In a group project I have to write a table to an Excel sheet. This I have done but I need to highlight the table area where the data goes, as can be seen on these pictures:
https://gyazo.com/51c57897d9a1ce8df000d6ff0f18de20
https://gyazo.com/bcc879cd7d1c5f12ccb853490dca22f2
The first picture shows how it should look without data, and the second picture shows my current file with the data loaded.
Is it possible to highlight like it is seen in the first picture where the data is supposed to be?
I have not been able to find any sources dealing with this online.
Here is the code that creates the Excel sheet. Take note that I have not looked into formatting the code properly, but it should be readable:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ExcelLibrary.SpreadSheet;
using System.Data;
using System.IO;
using System.Windows;
using Excel = Microsoft.Office.Interop.Excel;
namespace ProjectXstaal
{
class Print
{
public void LoadToExcel(DataTable dt)
{
string filetest = "filetest.xlsx";
double allHours = 0;
double overtimeHours = 0;
if (File.Exists(filetest))
{
File.Delete(filetest);
}
Excel.Application oApp;
Excel.Worksheet oSheet;
Excel.Workbook oBook;
oApp = new Excel.Application();
oBook = oApp.Workbooks.Add();
Excel.Worksheet ws = (Excel.Worksheet)oApp.ActiveSheet;
// Calculates the total hours worked and total overtime hours. not important for the question
for (int i = 0; i < dt.Rows.Count; i++)
{
string overtimeTemp = dt.Rows[i][3].ToString();
string temp = dt.Rows[i][2].ToString();
double temp2 = Double.Parse(temp);
double temp3 = Double.Parse(overtimeTemp);
overtimeHours += temp3;
allHours += temp2 + temp3;
if (i >= 40)
{
break;
}
}
// some formatting of the page
ws.Cells[3, 1] = "Tidsperiode:";
ws.Cells[3, 5] = "NAVN";
ws.Cells[3, 6] = dt.Rows[1][7].ToString();
ws.Cells[1, 5] = DateTime.Now.Year.ToString();
ws.Cells[1, 3] = "ARBEJDSSEDDEL";
ws.Cells[40, 1] = "SAMMENLAGT FOR UGEN";
ws.Cells[40, 5] = allHours;
ws.Cells[41, 1] = "UGENS TIMER FORDELES PÅ";
ws.Cells[43, 5] = overtimeHours;
ws.Cells[42, 5] = allHours - overtimeHours;
ws.Cells[42, 4] = "NORMALTIMER";
ws.Cells[43, 4] = "OVERARBEJDE";
ws.Cells[6, 1] = dt.Columns[1].ToString();
ws.Cells[6, 2] = dt.Columns[5].ToString();
ws.Cells[6, 3] = dt.Columns[0].ToString();
ws.Cells[6, 4] = dt.Columns[4].ToString();
ws.Cells[6, 5] = dt.Columns[2].ToString();
ws.Cells[6, 6] = dt.Columns[3].ToString();
ws.Cells[6, 7] = dt.Columns[6].ToString();
//prints the datatable to the excel sheet and stops when it cant fit anymore information
for (int i = 0; i < dt.Rows.Count; i++)
{
ws.Cells[i + 7, 1] = dt.Rows[i][1].ToString();
ws.Cells[i + 7, 2] = dt.Rows[i][5].ToString();
ws.Cells[i + 7, 3] = dt.Rows[i][0].ToString();
ws.Cells[i + 7, 4] = dt.Rows[i][4].ToString();
ws.Cells[i + 7, 5] = dt.Rows[i][2].ToString();
ws.Cells[i + 7, 6] = dt.Rows[i][3].ToString();
ws.Cells[i + 7, 7] = dt.Rows[i][6].ToString();
ws.Cells[i + 7, 1].Bold = true;
if (i >= 32)
{
break;
}
}
// Sets column width of the data.
ws.Range["A6"].ColumnWidth = 11;
ws.Range["B6"].ColumnWidth = 10;
ws.Range["C6"].ColumnWidth = 6.7;
ws.Range["D6"].ColumnWidth = 11;
ws.Range["E6"].ColumnWidth = 11;
ws.Range["F6"].ColumnWidth = 15;
ws.Range["G6"].ColumnWidth = 15;
oBook.SaveAs(filetest);
oBook.Close();
oApp.Quit();
MessageBox.Show("Det virker måske");
}
}
}
If you now the range which should be bold, use:
Microsoft.Office.Interop.Excel.Range range = xlWorkSheet.get_Range("A1:A6","G1:G6");
range.Font.Bold = true;
In this example, the first 6 rows and the first 7 seven columns get bold, assuming the cell in the top-left corner is "A1".
I hope this helps!

Excel.Range Copy() works very slowly

I'm building a report in which try to copy the previous row cell styles in the following
for (int i = 0; i < DataSource.Length; i++)
{
int rowNumber = i + s;
Excel.Range RngToCopy = ObjWorkSheet.get_Range("A" + rowNumber.ToString(), "K" + rowNumber.ToString());
Excel.Range r = ObjWorkSheet.get_Range("A" + (rowNumber + 1).ToString(), "K" + (rowNumber + 1).ToString());
RngToCopy.Copy(Type.Missing);
r.Insert(Excel.XlInsertShiftDirection.xlShiftDown);
r.PasteSpecial(Excel.XlPasteType.xlPasteFormats,
Excel.XlPasteSpecialOperation.xlPasteSpecialOperationNone, false, false);
ObjWorkSheet.Cells[rowNumber, 1] = i + 1;
ObjWorkSheet.Cells[rowNumber, 2] = DataSource[i].TerminalName;
ObjWorkSheet.Cells[rowNumber, 3] = DataSource[i].Type;
ObjWorkSheet.Cells[rowNumber, 4] = DataSource[i].Requisite;
}
everything works but very long
How can I speed this up?
I think you manually copy you will be improved.
Object[] origData = origRange.Value2;
destRange.Value2 = origData;
That should be WAY faster.

Sorting by Name (alphabetic) - Dual arrays [duplicate]

This question already has an answer here:
Closed 11 years ago.
Possible Duplicate:
Sorting by Name (alphabetic)
Say I have the code below. I have a total of 6 radio buttons. I have the 5 of the radio buttons working. The last is called radio button is called rbRegion. I believe I have everything set up correctly. There are two arrays, one for strings, and one for 4 quarterly totals and one yearly total. Say I wanted to sort by region name, I would place it in the `if (rbRegion.Checked) area. What exactly would I need to place in there to sort it alphabetically and to change the corresponding numeric array.
private void btnSort_Click(object sender, EventArgs e)
{
int n;
decimal temp;
int sortCol = 0;
string ntemp;
bool swapFlag;
if (rb1.Checked)
sortCol = 0;
if (rb2.Checked)
sortCol = 1;
if (rb3.Checked)
sortCol = 2;
if (rb4.Checked)
sortCol = 3;
if (rbTotal.Checked)
sortCol = 4;
if (rbRegion.Checked)
{
}
else
{
do
{
swapFlag = false;
for (n = 0; n < lastIndexUsed; n++)
{
if(quarters[n,sortCol] < quarters[n+1, sortCol])
{
//column 4
temp = quarters[n, 4];
quarters[n, 4] = quarters[n + 1, 4];
quarters[n+1, 4] = temp;
//col 3
temp = quarters[n, 3];
quarters[n, 3] = quarters[n + 1, 3];
quarters[n + 1, 3] = temp;
//col 2
temp = quarters[n, 2];
quarters[n, 2] = quarters[n + 1, 2];
quarters[n + 1, 2] = temp;
// col 1
temp = quarters[n, 1];
quarters[n, 1] = quarters[n + 1, 1];
quarters[n + 1, 1] = temp;
//col 0
temp = quarters[n, 0];
quarters[n, 0] = quarters[n + 1, 0];
quarters[n + 1, 0] = temp;
//name
ntemp = Branch[n];
Branch[n] = Branch[n + 1];
Branch[n + 1] = ntemp;
swapFlag = true;
}//endif
}//for end
} while (swapFlag);
}
If the value inside the rbRegion.Checked condition is an array. you can use this code.
Array.Sort(YourStringArray); // Ascending
Array.Reverse(YourStringArray); // Descending

Categories

Resources