Use autosave with numeric condition - vba

I am looking for a way to use autosave in VBA if an evolving numeric condition is met. Basically, I am looping through a variable called 'input_row' and I would like to use a condition that tests whether that variable is a multiple of 25 for instance:
If input_row = (random integer) * 25 Then
ActiveWorkbook.AutoSave
End If
Given that my code is constantly crashing due to issues with IE8, as discussed here, here making sure to autosave now and then seems pretty important. At the moment I am saving after every iteration in my loop which works fine but slows down the entire process quite a bit.
Any simple 'if' statement suggestion?

Use the Mod function to test if your number is a multiple of 25:
If input_row Mod 25 = 0 Then
'input_row is a multiple of 25
End If

Related

IF statement error despite the check being FALSE and the [value_if_false] being 0 or 1

For my own amusement I am trying to automate a project from work to learn more about excel vba. For the primary tab of data, I have an import function that drags in the relevant columns from another sheet for columns A through J. After that, there are a bunch of columns already set up to manipulate the the data being imported.
One of the calculation columns is supposed to return a basic 0/1 flag if the related company has been a client for >20 years. However, it ended up being a very slow UDF, so I wrapped it in an If statement to check if any other flags are false first so I can skip the slow calculation if the claim is already being eliminated. It worked fine before I went back to tweaking the import macro. Here is the function:
=IF( Q2*O2*N2 = 0, 0, IF(CompanyYears(J2, End_of_Claim_Period, Analysis_Width) >= Valid_Co_Years, 1, 0))
So now after the data import the only two results the column gives are 0 and #VALUE!. However, the 'evaluate function' step through confused me more. Turns out that for every value error, the 3 flags from columns Q/O/N are 1. So first the evaluate looks up and multiplies those 3 flags, gets 1=0 -> FALSE. The next thing it does is resolve what the named range End_of_Claim_Period points to. While it successfully changes it to a cell address, the outer IF statement's value_if_true changes from 0 to #N/A at the same time. The inner if statement continues just fine to a result of 0 or 1, and finally the statement
=IF(FALSE, #N/A, 1)
or
=IF(FALSE, #N/A, 0)
gets evaluated to #VALUE!.
Also, if I try to filter that column to see only the rows with a #VALUE! response, it correctly reevaluates them to the appropriate 0/1 values. I tried having the vba code filter then unfilter the row automatically but that leaves the errors in place still.
Update: While working on something else I came across a somewhat similar question here:
Excel is not updating cells, options > formula > workbook calculation set to automatic
I added Application.CalculateFull in at the end of the macro, which technically solved my problem, albeit for a notable performance hit.

What is the best/fastest method of filling an array with numbers between two values?

I've got a background thread which adds numbers to an array, this call happens often so i'm just curious if there's a faster method of adding the numbers to the array?
I need to add all the numbers between two values (values will be different depending on the situation), example 1 to 4 which would add 1,2,3 & 4.
However, when I make the call, it would be adding much larger arrays similar to 500 to 1000 etc which sometimes takes a little longer depending on how many numbers need to be added.
At the moment i'm using something similiar to this:
Dim ListOfNumbers As New List(Of Integer)
For i = 1 To 100000
If ListOfNumbers.Contains(i) = False Then
ListOfNumbers.Add(i)
End If
Next
Is there any other method that I could use which might be faster?
(Avoiding duplicate values in the array if possible)
I doubt this is driving your program's performance. Moreover, the best option may depend on how you plan to use these numbers, where you may find you actually can noticeably improve performance by using something like IEnumerable throughout your code, rather than an array.
With that in mind, I suggest this option:
int start = 1; int stop = 100000;
var list = Enumerable.Range(start, stop - start).ToArray()
Such that you can easily remove the ToArray() later if desired.
As for the existing code... You control both the List and the loop. Checking .Contains()is not necessary, and probably taking up a significant part of the execution time here. Just remove that check. You can also optimize some by pre-setting the size of the list:
Dim size As Integer = 100000
Dim ListOfNumbers As New List(Of Integer)(size)
For i = 1 To size
ListOfNumbers.Add(i)
Next

Optimal Method of Checking Keypresses on TI-89

for an experiment I decided to program a little game into my TI-89 using the built in program editor, however I cannot figure out an optimal method of getting keystrokes without significant delay. Currently I have:
Prgm
70→xpos
70→ypos
Loop
If getKey()=340 Then
xpos+3→xpos
PxlCrcl ypos,xpos,5,1
EndIf
If getKey()=337 Then
xpos-3→xpos
PxlCrcl ypos,xpos,5,1
EndIf
If getKey()=257 Then
Goto end
EndIf
EndLoop
Lbl end
EndPrgm
This creates an endless game loop that checks if the left, right, or delete buttons are being pressed and draw a circle left or right accordingly or end the program entirely. However, this method seems to run extremely slowly and I have seen much smoother movement in other demonstrations. Is there something wrong with my method and if so how can I improve it?
Sorry, I use a TI-84, but this method should still work.
The getKey() function is the function that is creating a delay. You only have to run the getKey() function once if you put the output into a variable. In TI-84, you can just do
getKey->K
You should be able to do exactly the same thing with TI-89.
Hope this helps!
What I usually do is use a While not() statement then check the answer afterwards.
For example
loop
0 -> X
while not(X)
do something every iteration
getKey()
if Ans: Ans -> X
Check values of X with If statements
End loop
In this way you are just executing some code (Maybe some basic addition and subtraction or a For loop to slow things down) and a single If statement on each loop of the While statement instead of checking a lot of If statements on each loop.
This serves you well and allows you to do something on each iteration of the While loop while still checking for a keypress.
Note that I usually program on TI-84s, but the idea should work much the same in the TI-89 with a bit of tweaking.

Excel VBA repeated change of a control cell hogs memory

I have searched on the web quite extensively, but have not managed to find any similar experiences. Any ideas?
I have a simple subroutine in VBA that changes a control cell. This control cell is used by the formulae in another sheet. As the code changes the control values, Excel uses increasingly more and more ram to the point that excel comes to a halt.
Basically I have a sheet setup that has 3000 rows and 330 columns. In each cell of the sheet the same formula below is populated:
=sum(sheet1!F8:INDEX(sheet1!F8:F$3000,Control!$D$1))
So in cells A1 you would have the formula above and in cell say B1 you would have:
=sum(sheet1!F**9**:INDEX(sheet1!F9:F$3000,Control!$D$1))
The control value that the code changes is Control!$D$1 and therefore changing control say from 2 to 4 will result in calculating running Sums from 2 to 4 consecutive rows in sheet1.
Note the code starts by setting a high value in the control cell (200) and works its way down to 2. The memory usage increase is therefore really baffling me.
The code I have is:
For i = 200 To 1 Step -1
Application.Calculation = xlCalculationManual
ClearClipboard 'sets cutcopymode to false
Range("Control!d1").Value = i
Application.Calculation = xlCalculationAutomatic
Next i
Finally I have tried the following alternatives and none of them suited me:
Doing all calculations in VBA arrays: Since VBA is not multithreaded, this is painfully slow (the point is to take advantage of my cpu cores using formulae in excel worksheets)
Setting screenupdating = false, enablevents = false, cutcopymode = false have no significant improvements
Converting formulae to values and reentering formulae by VBA: It again slows down the calculations
Manually reducing the number of processors: Defeats the purpose of my method as I need fast calculations
Is this an excel bug?
I have done some more research on your problem. The way your running sum function is built a lot of intermediate ranges have to be created:
=sum(sheet1!F8:INDEX(sheet1!F8:F$3000,Control!$D$1))
First, sheet1!F8:F$3000, second the result of the INDEX() function, third the argument to SUM().
Instead, I propose to only construct one range (the bare minimum) using the OFFSET() function. It lends itself to the task as the control parameter is a scalar and OFFSET() creates a new range from a range and scalars.
The running sum then is
=SUM(OFFSET(sheet1!$A$1;ROW()-1;COLUMN()-1;Control!$D$1;1))
where the control value merely sets the size of the range to be summed. In my tests with 2000 x 14 cells and 200 loops there was no increase in memory consumption to be observed. As both methods (INDEX() and OFFSET()) were quite fast for a sheet that size I cannot make any assumptions about calculation time (but see below for hints).
I have added the ROW() and COLUMN() functions to make the formula self-adjusting - the start address for the sum will be the identical address of the cell the formula is in. This way, all formulas on the sheet are exactly identical and do not have to be changed depending on their location.
As to the runtime, I would suggest you leave changing the Calculation Mode out of the loop (i.e. as automatic). I have noticed a huge overhead of several seconds for each change of mode. After changing the control cell all dependent cells have to be calculated once, and setting the mode to manual will not change that.
Lastly, if you try this formula with your original data, test whether leaving out the ClearClipboard command will have any effect. Ultimately it will have to call a Windows function thus leaving the Excel process environment, and I cannot see why it is needed here anyway except for cosmetic purposes.

How to prompt messagebox once inside a for loop in vb.net?

Is it possible to display a single messagebox inside a for loop codes?
I am trying to but cannot successfully make it.
Please help.
Thanks in advance.
Code inside a loop, by definition, is meant to execute multiple times, for each iteration of it, so if you don't want to have multiple messages, move that call outside of the loop so it executes only once. This would be the main way of doing so, because it makes it clear that there will be ever only one of them.
Otherwise, you can condition its display, by some particular condition that's warranted to happen only once, possibly caching the result from the user. The second snippet from phadaphunk does something like that.
From you question, I get that you don't understand how it works below.
The loop is a set of instructions that must be executed "x" number of time. So everything that is in the body of that loop will be executed that number of time. Which means that if there are 5 iterations to the loop, you will get 5 messagebox.
This is how you do it if you want a different box for each iterations :
For Each x As Integer In someList
MessageBox.Show(x.ToString());
Otherwise you can't do it unless there is a certain condition that explains to the compiler at which iteration you want the message box to appear. Something like
For Each x As Integer In someList
If (x == 5)
MessageBox.Show(x.ToString());