How can I smooth out my time ETA?

So in this script I’m working on, theres a repeat loop that runs many times. Its doing the exact same thing each time, but I don’t know how many times it’s going to run. But because each step is doing the same task, its very safe to assume they’re all going to take about the same size.

So after each slice through the loop, I update my progress bar with an ETA. The way I get that ETA is by taking the percentage done that I am (but as a floating point number between 1 and 0, not as an actual percentage.

Then I divide the amount of seconds I’ve been running the loop, by that faux percentage number.

And presto, I have a pretty good estimate of when my script is going to be done. But here’s the problem. Due to minor changes in speed, the ETA number bounces all over the place for the first 15 minutes or so. It’s REALLY all over the place right at the start.

So how can I smooth that out?

My first thought was what I would try if this were a PHP script… I’d store the last 10 ETA’s in an array. Every time I calculate a new one, I’d put it at the start of the array, and delete the time at the end of the ETA. Then I would take an average of the 10 numbers, and that’s what I would actually display.

But AppleScript doesn’t have a lot of array functions like normal languages do, so that seems like way more hassle than its worth?

Welp I did it the array way anyway and I guess it wasn’t that bad. I haven’t tested it yet though, I will in a few minutes.

Ack I already see a mistake, I forgot to set a threshold for the number of items for the array, so this will always have an array with just one value in it. Ok fixed. . .

copy ETAInSeconds to end of ETArray
if (count items in ETArray) is greater than ArrayThreshold then
	set ETArray to items 2 thru -1 of ETArray
end
set ETArraySum to 0
repeat with q in ETArray
	set ETArraySum to ETArraySum + q
end repeat
set ETAInSeconds to round (ETArraySum / (count items in ETArray))

ETAInSeconds is the estimated total amount of seconds the script is going to take to run, rounded to an integer, previously calculated in the script. And ArrayThreshold is 10. But I might make it higher, we’ll see how smooth the number gets.

Seems to be working well. Definitely smoother results. Smooth meaning the amount the time jumps around is much smaller. That said, I realize that part of the reason its still unappealing to the eyes is how often it updates, which is a few times per second. It would be better if I could set some kind of time based trigger so it only updated the time ever 2 or 3 seconds, but theres no easy way to do that.

Stills, this is an improvement and is good enough I think.
One question is, given that I’m snipping an item off an array and adding another item to the end of the array, potentially tens of thousands of times as this script runs, is that potentially going to cause a problem? Like memory leaks or pointer overflows or anything?

You can use the MOD function to only update every 2 or 3

set doUpdate to ((currentIndex MOD 3) == 0) as boolean 

if doUpdate then
— update your progress here
end if

I thought of that but the problem is, while all of the actions in a particular run are identical, on different runs you can choose different actions. So a mod 4 on the smallest action might get you one eta update every seconds, but a mod 4 on the largest action will only update the timer every 16 seconds or so.

Check out this I just came across:

https://www.script-factory.net/XModules/LapTime/en/index.html