how can i calculated values after Worksheet.Calculate()? - c#

i tried Trial version of Gembox.SpreadSheet.
when i Get Cells[,].value by for() or Foreach().
so i think after Calculate() & get Cell[].value, but that way just take same time,too.
it take re-Calculate when i Get Cell[].value.
workSheet.Calcuate(); <- after this, values are Calculated, am i right?
for( int i =0; i <worksheet.GetUsedCellRange(true).LastRowIndex+1;++i)
{
~~~~for Iteration~~~
var value = workSheet.Cells[i,j].Value; <- re-Calcuate value(?)
}
so here is a Question.
Can i Get calculated values? or you guys know pre-Calculate function or Get more Speed?

Unfortunate, I'm not sure what exactly you're asking, can you please try reformulating your question a bit so that it's easier to understand it?
Nevertheless, here is some information which I hope you'll find useful.
To iterate through all cells, you should use one of the following:
1.
foreach (ExcelRow row in workSheet.Rows)
{
foreach (ExcelCell cell in row.AllocatedCells)
{
var value = cell.Value;
// ...
}
}
2.
for (CellRangeEnumerator enumerator = workSheet.Cells.GetReadEnumerator(); enumerator.MoveNext(); )
{
ExcelCell cell = enumerator.Current;
var value = cell.Value;
// ...
}
3.
for (int r = 0, rCount = workSheet.Rows.Count; r < rCount; ++r)
{
for (int c = 0, cCount = workSheet.CalculateMaxUsedColumns(); c < cCount; ++c)
{
var value = workSheet.Cells[r, c].Value;
// ...
}
}
I believe all of them will have pretty much the same performances.
However, depending on the spreadsheet's content this last one could end up a bit slower. This is because it does not exclusively iterate only through allocated cells.
So for instance, let say you have a spreadsheet which has 2 rows. The first row is empty, it has no data, and the second row has 3 cells. Now if you use 1. or 2. approach then you will iterate only through those 3 cells in the second row, but if you use 3. approach then you will iterate through 3 cells in the first row (which previously were not allocated and now they are because we accessed them) and then through 3 cells in the second row.
Now regarding the calculation, note that when you save the file with some Excel application it will save the last calculated formula values in it. In this case you don't have to call Calculate method because you already have the required values in cells.
You should call Calculate method when you need to update, re-calculate the formulas in your spreadsheet, for instance after you have added or modified some cell values.
Last, regarding your question again it is hard to understand it, but nevertheless:
Can i Get calculated values?
Yes, that line of code var value = workSheet.Cells[i,j].Value; should give you the calculated value because you used Calculate method before it. However, if you have formulas that are currently not supported by GemBox.Spreadsheet's calculation engine then it will not be able to calculate the value. You can find a list of currently supported Excel formula functions here.
or you guys know pre-Calculate function or Get more Speed?
I don't know what "pre-Calculate function" means and for speed please refer to first part of this answer.

Related

Trying to delete an entry from a structure array in C#. Getting conflicting information?

I have been researching this topic and got conflicting answers. Any help is appreciated.
For an assignment, I am instructed to create a structure of arrays. I am trying to delete an entry in one case, and change in another. This is supposed to be by one of the fields and not by index number.
var countOfEmployees = 0;
var employees = new EmployeeData[100];
Console.Write("Please enter employee you want to delete:");
string deleteEmployee = Console.ReadLine();
bool deleted = false;
for (int x = 0; x < countOfemployees; x++)
{
if (items[x].ItemNumber == deleteItemNumber)
{
deleted = true;
}
if (true)
{
//code goes here
}
Any help is appreciated!
In an array, you might be able to delete the value from the place holder, but you will not be able to remove the actual item without some footwork.
Basically, what you can do is: Find the value you've searched for, and replace it with a null and treat it orrespondingly in every other function.
Option 2 would be to remove the item and then use a function that would "shift" all the values with a higher index upwards.
Option 3 is to use the advanced functions C#/.NET has to offer with collections, create a List, remove the item and cast back to an array.
var employees = new EmployeeData[100];
var list = employees.ToList();
int index=-1;
//search through in a loop (won't write it here)...
index = x; //get the index in your list then break the loop
break; //end the loop
list.RemoveAt(index); //delete the spot outside the loop
employees=list.ToArray();
Of course there's checks needed if the search didn't find anything, but i think you can manage to implement that without my help.
And this is of course me assuming that there's only ONE entry with that kind of value in the array.
If it's not, you're gonna have to loop through and erase them until the search doesn't find anything anymore.

Using DataGridView in Visual Studio C#

I have a string that contains: "# of rows, # of columns, Row'X'Col'X'=Serial#, ...
How do I create a DataGrid table with the number of rows and columns defined, and then place the serial #s into the grid.
Examples:
2,1,R1C1=111,R2C1=112,
2,2,R1C1=211,R1C2=212,R2C1=213,R2C2=214,
thanks
Below is code that does what you are asking; however I must point out some problems with this approach. First, getting the total rows and cols from the first two elements in order to create your table is risky. If that data is wrong, this code will most likely crash or possibly omit data. Example if the input is: 2,2,RXCX=.., RXCX=.., RXCX=.., RXCX=..,RXCX=, RXCX=… This line will only get the first 4 values.
Worse… this will crash… if the input is 2,2,RXCX=.., RXCX=.. Then it will crash when you try to access the 4th element in the splitArray because there isn’t a 4th element. Either way is not good.
My point is to be safe… it would be a better approach to see how much data is actually there before you create the grid. You could get how many items there are with StringArray.Length minus the first two elements. These elements will define the dimensions and allow you to check their validity. This will make sure your loops won’t go out of bounds because the supplied data was wrong. It seems redundant and error prone to supply the dimension values when you can get that info from the data itself.
I still am not 100% sure what you want to accomplish here. It looks like a search of some form. This is what I am picturing…
Looking at your (previous) screen shots it appears to me that after you type into the Serial # text box and click the “Search Txt Files” button it will search for data that came from the input string i.e. “PLX51…” and then have the grid display the “filtered” results that match (or are LIKE) what’s in the Serial # textbox. If this is true, I would ignore the RXCX vales and put the data in a single column. Then wire up an OnKeyPress event for the text box to filter the grid whenever the user types into the Serial # text box.
Otherwise I am lost as to why you would need to create the data in the fashion described. Just because the input has unnecessary data… doesn’t mean you have to use it. Just a thought.
string inputString = "2,2,R1C1=211,R1C2=212,R2C1=213,R2C2=214";
string[] splitArray = inputString.Split(',');
int totalRows = int.Parse(splitArray[0]);
int totalCols = int.Parse(splitArray[1]);
int itemIndex = 2;
// add the columns
for (int i = 0; i < totalCols; i++)
{
dataGridView1.Columns.Add("Col", "Col");
}
// add the rows
dataGridView1.Rows.Add(totalRows);
for (int i = 0; i < totalRows; i++)
{
for (int j = 0; j < totalCols; j++)
{
dataGridView1.Rows[i].Cells[j].Value = splitArray[itemIndex];
itemIndex++;
}
}

How to get only selected cells value from filtered cells from excel

I have a simple excel sheet:
Now, I filter it such that cell value > 1. Now my data looks like:
Now, I select the data that I require:
Note that I have selected all the Mobile Numbers.
Now in my code, I am trying to retrieve all the selected data as follows:
Range selection = (Range)Globals.ThisAddIn.Application.ActiveWindow.Selection;
But, it gives me the cells from starting to ending. I think excel selects the non-visible rows also. Because row no 4 that contains 0 is also retrieved. Look at the image below:
So, now I created another Range and tried to add all the values of cells that are visible as follows:
Range onlyFilteredSelection = selection.Cells.SpecialCells(XlCellType.xlCellTypeVisible);
Now, I can see that c# shows me only the two rows. Why is it not displaying the last row, which is after the non-filtered row. Take a look at the values here:
Update:
After posting this question, I got a thought in my mind that I might be getting multiple ranges instead of 1 and so, I started exploring. And look what I have found. I found that I was exactly right. I get multiple ranges.
Here is the code that I have tried:
Range selection = (Range)Globals.ThisAddIn.Application.ActiveWindow.Selection;
List<Range> onlyFilteredSelection = new List<Range>();
foreach (Range range in selection.Cells.SpecialCells(XlCellType.xlCellTypeVisible))
{
onlyFilteredSelection.Add(range);
}
Now, I get 4 items in selection variable. And in onlyFilteredSelection has got 3 items.
Now, I am in another trouble:
Previously, I was getting a Range, so I converted it to a Comma-Separated String very much easily using the below mentioned code:
string[] AllRecepientMobileNumberValues = ((Array)(selection.Cells.Value2)).OfType<object>().Select(o => o.ToString()).ToArray();
string RecepientMobileNumberValue = AllRecepientMobileNumberValues.Aggregate((a, x) => a + ", " + x);
But now, I get a List. So, now my big question is how to Convert a List to Comma-Separated string?????????
You can use one more Select to get the values out of a list.
string[] AllRecepientMobileNumberValues = onlyFilteredSelection.Select(x => x.Cells.Value2).OfType<object>().Select(o => o.ToString()).ToArray();
string RecepientMobileNumberValue = AllRecepientMobileNumberValues.Aggregate((a, x) => a + ", " + x);
I tried around a bit and had problems too. But I think I may have found a possible workaround for your situation. First some things I found out.
I was able to reproduce your behaviour
the selection of all visible cells fails, because a filter (seems?) not to hide the rows, but it set the row height to 0!
I could not find any other useful method/property when looking around on the Application Member or the Range Member.
I created a macro to record what VBA code would be generated on a copy action of your selection´too. Strange thing is that there is nothing special in the code as you can see.
vba macro code
Range("A3:A5").Select ' correct as three lines are selected,
' but only two of them have a rowHeight > 0
Selection.Copy
Range("F8").Select
ActiveSheet.Paste ' and here is the magic?? why does vba only paste 2 cells??
So I decided to come up with a workaround. Why not simulation what VBA seemingly does too. Only handle those cells whose rowHeight > 0.
exampleCode.cs
private static void readFilteredCells()
{
Excel.Application xlApp = (Excel.Application)Marshal.GetActiveObject("Excel.Application");
Workbook xlBook = (Excel.Workbook)xlApp.ActiveWorkbook;
Worksheet wrkSheet = xlBook.Worksheets[1];
Range selection = xlApp.Selection;
for (int rowIndex = selection.Row; rowIndex < selection.Row + selection.Rows.Count; rowIndex++)
{
if (wrkSheet.Rows[rowIndex].EntireRow.Height!=0)
{
// do something special
}
}
}
I hope my answer is of any use for you. If you need any further assistance please let me know.

Takes too long to loop through array looking for duplicates

hope you can help me out.
I've got a 135.000 line long txt file containing lines like this: 111706469;1972WE;26;Wel.
What the program is supposed to do, is compare every line to every line that came before it, to find if it's more than 80% similar and then state the line number of the original line.
Those things i've managed to do on my own like this.
if (rows.Length > 1) {
for (int rowIndex = 1; rowIndex < rows.Length; rowIndex++)
{
string cols = rows[rowIndex];
bool Dubbel = false;
for (int DupIndex = 0; DupIndex < rowIndex; DupIndex++)
{
string SearchDup = rows[DupIndex];
decimal ComparisonResult = Compare(cols, SearchDup);
if (ComparisonResult > 80)
{
cols += ";" + DupIndex;
Dubbel = true;
break;
}
}
Console.WriteLine(rowIndex + ";" + cols);
}
}
This means the program has to go through the array again and again for every array item. My question is, is there a faster/better way to doing this?
Any help you can give me would be much appreciated.
The problem is with your fuzzy matching, which returns a floating point number - there's no way to optimize this better than O(N*N) without any details on the fuzzy function itself (if I'm wrong - please somebody correct me)
If you have exact matches you can remove them first, this way your N^2 complexity will be reduced to (N-K)^2 - this operation will be worth it if you have at least some exact matches.
Use HashSet<>, which doesn't need a second object like Dictionary
List<string> rows = new List<string>(new[] {"AAA","BBB","AAA","CCC"});
HashSet<string> foundLines = new HashSet<string>();
foreach (string row in rows){
if (!foundLines.Contains(row))
foundLines.Add(row);
}
rows = foundLines.ToList();
Then proceed with your algoritm
You're not going to be able to get much optimization without a significant overhaul. It'd be trivial for exact matches, or for searching for anything which closely matched a target, but for a difference between objects, you must compare each item to each previous item.
Basically, if you're given a set of N strings, you have to compare N to N-1, N-2, N-3, etc. Then you need to compare them all again with N+1, in addition to N, because there's no relationship between N+1 and N.
After some further efforts I've come to the anwser of my own question and thought I should post it incase someone else were to have the same problem.
I converted the txt file to a mysql database, then SELECTED'ed all the records once into a DataTable. The code then loops through the records and SELECT's from the original DataTable only those records with the same Postal code and house number into a second DataTable. Against which the original is compared.
This reduced a process that took 9 hours to 2 to 3 minutes. After the fact it was quite obvious, but such is hindsight...
Hope it helps someone out.

How to put array into excel range

I know how to write single cell into excel but when im trying it on array excel sheet is filling with only last value
this is my range
Excel.Range ServiceName = (Excel.Range)_sheet.get_Range(_sheet.Cells[38, "B"] as Excel.Range, _sheet.Cells[45, "B"] as Excel.Range);
_ServiceName is List which contains 1,2,3,4,5,6
for (int i = 0; i < _ServiceName.Count; i++)
{
ServiceNameArray[0, i] = _ServiceName[i];
}
this i my trying to write into excel but as i said it there is only last item (6) in excel book
for (int i = 0; i < _ServiceName.Count; i++)
{
ServiceName.set_Value(Type.Missing, ServiceNameArray[0,i]);
}
does anyone have an idea?
Davide Piras is right. And you're doing a few other strange things there, I can elaborate by request.
For now I just want to point out that you can directly assign the .Value property of a Range to an array:
ServiceName.Value2 = _ServiceName.toArray();
This is much, much faster for bigger amounts of data.
(Side note: If you want to do the same with Formulas, for some strange reason you have to take an extra step (doubling the time):
range.Formula = array;
range.Formula = range.Formula;
unless there is a better way I don't know about yet.)
I see you looping on the ServiceName array to get all values one after the other but not see you changing the focused cell inside the cellrange at every loop iteration. Of course, I would say, you see only the last value, because you are writing all values one over the other always in the same place.

Categories

Resources