
GetIndexedObject and unstable indizes

thomas_braun
I have the following code
Function DoStuff() variable numEntries, i string str, path NewDataFolder/O root:tteest NewDataFolder/O root:tteest:a NewDataFolder/O root:tteest:ab NewDataFolder/O root:tteest:abc NewDataFolder/O root:tteest:abcd NewDataFolder/O root:tteest:abcde NewDataFolder/O root:tteest:abcdef DFREF tmpDFR = root:tteest numEntries = CountObjectsDFR(tmpDFR, 4) for(i = 0; i < numEntries; i += 1) str = GetIndexedObjNameDFR(tmpDFR, 4, i) path = "root:tteest:" + str printf "i=%d, path=%s\r", i, path DFREF dfr = $path if(CountObjectsDFR(dfr, 4) == 0) // only kill if empty KillDataFolder dfr endif endfor End
and got really puzzled today as this does not work as it outputs
i=0, path=root:tteest:a i=1, path=root:tteest:abcdef i=2, path=root:tteest:abcd i=3, path=root:tteest: i=4, path=root:tteest: i=5, path=root:tteest:
or alternatively
i=0, path=root:tteest:abc i=1, path=root:tteest:abcde i=2, path=root:tteest:abcd i=3, path=root:tteest: i=4, path=root:tteest: i=5, path=root:tteest:
It looks like the higher indizes are invalidated by the KillDataFolder call. Is that how it is supposed to work?
I can of course rework the code, but I would like to understand how CountObjects and friends work first.
Thanks,
Thomas
PS: I've found that with
#pragma rtFunctionErrors=1
turned on.
February 23, 2017 at 07:08 pm - Permalink
February 24, 2017 at 12:39 am - Permalink
With relevant help found here:
displayhelptopic "DataFolderDir"
Best,
_sk
February 24, 2017 at 01:35 am - Permalink
Deleting top down however seems to work. Using
yields
as expected.
HJ
February 24, 2017 at 01:46 am - Permalink
@aclight: This seems to exploit some implementation detail (linked list IIRC) of the datafolders.
@olelytken: Avoiding the second loop would be nice but seems difficult.
@_sk: Does that really differ performance-wise from getting all folders with
Make/T/N=(numEntries) folders = GetIndexedObjNameDFR(tmpDFR, 4, p)
? My guess is that DataFolderDir loops also over all folders.@HJDrescher: Nice idea!
I guess I will be using a precomputed list as olelytken and _sk suggested as this should also work with future Igor Pro versions as it does not exploit an implementation detail.
Thanks again!
Thomas
February 24, 2017 at 09:29 am - Permalink
February 24, 2017 at 11:05 am - Permalink
Just to be clear. With "loops" I meant to say "requiring igor to iterate over all datafolders".
February 24, 2017 at 11:36 am - Permalink
That's not exploiting any implementation detail. Your original code has two related problems. Outside of the loop, you get the number of children and store that in numEntries. That value is correct before you start the loop, but within the loop you are deleting some of the children without recalculating the value of numEntries. Furthermore, your iterator, i, increases with each trip through the loop, even when you kill one of the child objects.
In situations like this where you may be deleting items from a list of things, I typically iterate in reverse like HJDrescher suggested. However if for some reason you need to iterate forward, then my modifications to your code should work and aren't dependent on the underlying implementation of data folders.
In case it's still not clear, consider the following two functions:
Here's the output you get from them:
You'll also get a run time error with the first version when i >= 3 because the printf statement's "ddd[p]" will be out of range.
February 24, 2017 at 02:00 pm - Permalink
February 26, 2017 at 06:02 am - Permalink