I'm writing a c# Add in for excel that takes values from a column of an excel sheet and does some operations. This is a part of the code that I wrote:
Excel.Range aqRange = currentSheet.Range["C3:C" + cRowCount];
Excel.Range vcRange = currentSheet.Range["D3:D" + cRowCount];
Excel.Range k0R = currentSheet.Range["F2"];
double[] sgVett = new double[cRowCount];
foreach (Range aq in aqRange)
{
if (i == 0) sgVett[i] = k0R.Value + aq.Value;
else sgVett[i] = sgVett[i - 1] + aq.Value;
i++;
}
i = 0;
foreach (Range vc in vcRange)
{
if (i == 0) sgVett[i] -= vc.Value;
else sgVett[i] -= vc.Value;
i++;
}
I want to know if is there some way to do something like this:
for(int j = 0; j<cRowCount; j++) {
if (i == 0) sgVett[i] = k0R.Value + aqRange[i].Value;
else sgVett[i] = sgVett[i - 1] + aqRange[i].Value;
}
I know that I can't use a Excel.Range as a vector, but is there some way to use an index to scroll aqRange and vcRange or, at least, if it's possible to use just one for or one foreach instead of two (as I done).
You can use the Range's Cells property a bit like a 2 dimensional array.
It is important to note that although the syntax used is similar to a C# 2D array (Cells[RowIndex, ColIndex]), the Cells property accesses a COM object that uses 1 as it's start offset, rather than 0.
So you should be able to write something like :
for(int j = 1; j<=cRowCount; j++)
{
if (i == 0) sgVett[i] = k0R.Value + aqRange.Cells[j,1].Value;
}
Also see here : Fastest way to get an Excel Range of Rows & How do I get an Excel range using row and column numbers in VSTO / C#?
Related
I currently have a (somewhat messy) bubble sort of an object array called "sorted", the code is as follows
object storage = 0;
for (int i = 0; i < sorted.Length; i++)
{
for (int c = 0; c < sorted.Length - 1; c++)
{
if (sorted[c].ToString().CompareTo(sorted[c + 1].ToString()) > 0)
{
storage = sorted[c + 1];
sorted[c + 1] = sorted[c];
sorted[c] = storage;
}
}
return sorted;
Problem is that this function always loops through the array , no matter what. Hypothetically speaking the "sorted" array could be a large array and just so happen to be sorted already, in which case the function would still scan the array and work for some time, which I want to prevent.
So the question is, how do I stop the loop properly in case the array is sorted already?
A bubble sort bubbles the largest (smallest) element of an array towards the end of an array. This is what your inner loop does.
First of all you can take advantage of the knowledge that after n iterations, the last n elements are sorted already, which means that your inner loop doesn't need to check the last n elements in the (n+1)th iteration.
Secondly, if the inner loop doesn't change anything, the elements must be in sequence already, which is a good point for a break of the outer loop.
Since you're doing this as a practising exercise, I'll leave the coding up to you :-)
Why don't you use OrderBy instead of sorting it yourself?
sorted = sorted.OrderBy(s=> s).ToArray();
If you insist to use the bubble sort, you can do this:
bool changed;
for (int i = 0; i < sorted.Length; i++)
{
changed = false;
for (int c = 0; c < sorted.Length - 1; c++)
{
if (sorted[c].ToString().CompareTo(sorted[c + 1].ToString()) > 0)
{
changed = true;
storage = sorted[c + 1];
sorted[c + 1] = sorted[c];
sorted[c] = storage;
}
if(!changed) break;
}
I'm setting changed to false each time in the first loop. If there was no changes to the end, then the array is already sorted.
Try this:
object storage = 0;
for (int i = 0; i < sorted.Length; i++)
{
bool swapped = false;
for (int c = 0; c < sorted.Length - 1; c++)
{
if (sorted[c].ToString().CompareTo(sorted[c + 1].ToString()) > 0)
{
storage = sorted[c + 1];
sorted[c + 1] = sorted[c];
sorted[c] = storage;
swapped = true;
}
}
if (!swapped)
{
break;
}
}
If it gets through a pass without swapping then the array is ordered so it will break.
I've pretty much switched over to generic types and away from the array types but now and then I need to iterate through something where it is convenient to have indexes like those arrays provide. Generic lists are great because they keep the order of things internally the same as the order of things inserted, they grow dynamically and come with very useful methods but can I jump around like I can with arrays? Could I say, iterate a generic list using a for loop and on certain indexes get the value of past or future indexes without having to iterate over all of the values in between?
Example using an array:
for (int i = 50; i != 0; --i)
{
if (myArray[i] == 1 && i + 5 <= 50)
{
myArray[i + 5] = myArray[i + 5] + 2;
}
}
Yes you can do that with list just like arrays. List have indexers which act similar to array indexer. Did you try it and it not work?
var lists = Enumerable.Range(0, 51).ToList();
for (var i = 50; i != 0; --i)
{
if (lists[i] == 1 && i + 5 <= 50)
{
lists[i + 5] = lists[i + 5] + 2;
}
}
I have a multidimensional array that I'm using as a box, and I have code that generates a border around it, like this:
#######
# #
# #
# #
# #
#######
However what I don't understand is that I can have either a 0 or a 1 in the "j == ProcArea.GetUpperBound(...)" part and it works successfully without any errors or unexpected output.
int[,] ProcArea = new int[rows, columns];
//Generate border
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < columns; j++)
{
if (i == 0 || j == 0 || i == ProcArea.GetUpperBound(0) || j == ProcArea.GetUpperBound(1))
{
ProcArea[i, j] = 2;
}
}
}
Why does this work, and what is the correct value I should be using?
Thanks
If the number of rows and columns are the same, then GetUpperBound(0) and GetUpperBound(1) are going to return the same value.
Arrays you create in C# (unless you call Array.CreateInstance directly) are always 0-based. So GetUpperBound(0) will always return rows - 1, and GetUpperBound(1) will always return columns - 1.
So the code will "work" regardless of which upper bound you check, although I think you'll find that if rows != columns, then using GetUpperBound(0) will create a different sized box than GetUpperBound(1).
By the way, an alternate way of making your border would be:
var maxRow = ProcArea.GetUpperBound(0);
var maxCol = ProcArea.GetUpperBound(1);
// do top and bottom
for (int col = 0; col <= maxCol; ++col)
{
ProcArea[0, col] = 2;
ProcArea[maxRow, col] = 2;
}
// do left and right
for (int row = 0; row <= maxRow; ++row)
{
ProcArea[row, 0] = 2;
ProcArea[row, maxCol] = 2;
}
It's slightly more code, true, but you don't waste time checking indexes unnecessarily. Won't make a difference with small arrays, of course.
Check the documentation http://msdn.microsoft.com/en-us/library/system.array.getupperbound.aspx. Your array has 2 dimensions (rows and columns).
ProcArea.GetUpperBound(0) is equivalent to rows - 1
ProcArea.GetUpperBound(1) is equivalent to columns - 1
I have the following method:
public static object getValue(Excel.Worksheet sheet, int row, int col)
{
Excel.Range r = sheet.Cells[row, col] as Excel.Range;
//I've also tried using sheet.get_Range(cell, cell); here, with the same result
if (r.Row != row || r.Column != col)
{
//Why does this debug statement sometimes print?
Debug.Print("Tried to read (" + row.ToString() + ", " + col.ToString() + ") but got (" + r.Row.ToString() + ", " + r.Column.ToString() + ")");
}
return r.Value2;
}
Based on my understanding of Excel.Worksheet.Cells[row, column], my code should never enter the if statement. However, when I call getValue repeatedly to read multiple cells, every so often the row and column of the range it returns are different than the row and column I called Excel.Worksheet.Cells with.
Example output: "Tried to read (19, 1) but got (56, 5)"
Furthermore, if I break in the if statement, then rewind my execution point and run Excel.Worksheet.Cells again, I get the correct range.
Why could this be?
This isn't an answer to your direct question, but may solve the problem.
Is getValue in a tight loop? If so then I would approach it a different way. Since Accessing Cells and Value2 are COM-calls they are slower than normal array accessors. If you have a particular range you're looping over I would get the array of values for that range in memory and access the array directly rather than looping through the cells.
e.g. instead of
for(int r = 1; r <= 10; r++)
for(int c = 1; c <= 20; c++)
double val = sheet.Cells[r,c];
do
object[,] values = sheet.Range("A1:J20").Value
for(int r = 1; r <= 10; r++)
for(int c = 1; c <= 20; c++)
double val = values[r,c];
This may fix your problem by removing the COM access from tight loop and eliminating whatever problem is giving you the strange results.
I had a problem with deleting a row in c# .im writing a program for sky-l program and im checking the first coloumn and then i will decide which row is smaller(the first coloumn is important) plz help me how to delete the row. this the code.
for (int f = 0; f < i; f++)
{
sortedsky[f, 0] = sky[min, 0];
sortedsky[f, 1] = sky[min, 1];
sortedsky[f, 2] = sky[min, 2];
//how to delete???
for (y = 0; y < i-1; y++)
min = 0;
if (sky[y+1, 0] < sky[min, 0])
min = y;
}
return 1;
}
If you need to remove items from a list, consider using a List<T> instead of an array.
I strongly suggest using a generic List (which manages an array internally)
You can get a plain array from a list:
List<Sky> listofSky;
listofSky.Add(sky1);
listofSky.Add(sky2);
listofSky.Add(sky3);
Sky[] arr = listofSky.ToArray();
List also has simple Remove methods.