Recursive For Loop Function Not Returning Value

i am basically writing a recursive function that goes into each dictionary stored in the entire table to search for a specific animation array by simply only using the index. this is all inside a modulescript
You can write your topic however you want, but you need to answer these questions:

  1. What do you want to achieve?

the recursive function currently only returns nil, and i want to return the medium_s array in this instance. (not one given value, the whole table of {"ids are here", etc})

  1. What is the issue?

see above; by the way, the given value for AnimationId is medium_s (string). i have typechecked both of them like a million times

  1. What solutions have you tried so far?

the function successfully can go into each dictionary and read out all expected tables, i’ve confirmed this with print() checks…
image
(result):
image

and for some reason, the yellow highlighted output (given by the warn() in the for loop that is supposed to only run if the array i wanted was found ran anyways, even though returning it still yields nil
image

i saw some stuff about for loops being a non-callback and other loopholes others have found so here’s a list of stuff that hasn’t worked:

  • making a table in the function and inserting the array in there and then returning that_table[1] or nil. returns nil.
  • making a variable at the top and then setting to the found array, breaking and return said variable. returns nil
  • changing returns on the function callback for the else part of the if statement by removing/adding it, same for the tostring()s, does nothing to change output
  • changing cycling_table to be a general function parameter where ani_manager.ids would be inserted manually in parenthesis, still does not change it
  • i can’t make a global variable outside the function because this is a module to be used by all clients to quickly generate animations, so yea

here’s the code piece

ani_manager.ids = {
    combat = {
        medium_s = {
            "ids are here",
            "ids are here"
        },
        light_s = {},
        heavy_s = {}
    },
    casual = {
        idle = "",
        confirm = "",
        deny = ""
    }
}

function ani_manager.GetAnimationArray(AnimationId, OverridingTable)
    local cycling_table = OverridingTable or ani_manager.ids
    for index, array in pairs(cycling_table) do
        if tostring(index) == tostring(AnimationId) then
            return array
        elseif type(array) == "table" then
            return ani_manager.GetAnimationArray(AnimationId, array)
        end
    end
    return nil -- returns nil always for some reason
end

i’ve tried everything i can really think of for this and it still isn’t giving anything back. i know it’s this code segment here because when i put it the table in the function for running animations manually the animations play as intended, don’t know if it’s a scope issue or what. thoughts?

This is the issue in the loop. You’re basically returning any result returned by the recursive function call whether it was an actual table or not.
Instead, make this line as a local variable and check if it is not nil or if it was a table before returning it, otherwise, the loop will halt right after.

Here is the modification:

local result = ani_manager.GetAnimationArray(AnimationId, array)
if type(result) == "table" then
	return result 
end

Also, consider removing the unnecessary tostring functions, as they are not needed in this case.

What are you sending to find in the table when you run the function? I mean the AnimationId?
ani_manager.GetAnimationArray(AnimationId)

For a table like that, I suppose you are trying something like this? this is just for testing I changed it into a normal script not module:

local aniTable = {}
aniTable["combat"] = {
	medium_s = {"mediumID1", "mediumID2"},
	light_s = {"light_sID1", "light_sID2"},
	heavy_s = {"heavy_sID1", "heavy_sID2"}
}
aniTable["casual"] = {
	idle = "idleID",
	confirm = {"confirm_ID1", "confirm_ID2"},
	deny = "denyID"
}


local function GetAniArray(thingToFind)
	for index, array in pairs(aniTable) do
		print(index)
		if array[thingToFind] then
			return array[thingToFind]
		end
	end
end

local response = GetAniArray("medium_s")
warn(response)

And I get the array in the ouput from “medium_s”

I am not sure if this is related to what @EgizianoEG said. However, the reason why you are experiencing this is probably because you are recursing before you’ve gone through the whole dictionary. You are stopping at the first array provided to you, then checking if that array’s index is the same as the AnimationId.

I edited your function to fix this issue. Here it is:

function module.findArray(name, t)
	local cycleTable = t or module.myTable
	
	local arraysToCheck = {}
	
	for index, array in pairs(cycleTable) do
		if index == name then
			return array
			
		elseif typeof(array) == "table" then
			table.insert(arraysToCheck, array)
		end
	end
	
	for _, array in ipairs(arraysToCheck) do
		local found = module.findArray(name, array)
		
		if found then
			return found
		end
	end
	
	return nil
end

Also, creating a global variable inside of a module is safe. If a client changes a value in a module, that change will not replicate to the other clients. Otherwise, you should not have a global function, which defeats the purpose of the module.

Edit: Using the code snippet @EgizianoEG provided takes up less lines of code and works the same as mine.

This is my code using @EgizianoEG’s code snippet.

function module.findArray(name, t)
	local cycleTable = t or module.myTable
	
	for index, array in pairs(cycleTable) do
		if index == name then
			return array
			
		elseif typeof(array) == "table" then
			local found = module.findArray(name, array) -- "found" = "result"
			
			if found then
				return found
			end
		end
	end
	
	return nil
end

yea i had the problem only when working in the module, i had tested it on a reg script and it worked fine there

thanks, seems to have fixed the issue

for my own reference, was my prior function failing because it was stopping at those arrays? I would have thought the function would continue through the dictionaries rather than be stopped on for example the casual array

Your previous function was like running this:

for i = 1, 10 do
	if i == 10 then
		print("TEN!")
		
	else
		break -- This is just an example of you skipping the other iterations.
	end
end
1 Like

i had done this previously but had still no effect on the output; tostring() was a last test i did to check if the indexes weren’t correctly formatted or wtv, they’re getting removed

someone else’s method worked by completely rewriting the func, but i’ll try this separately as well

How?!
I’ve already tested it myself and the loop returns the desired array.
Here is the code I tested.

local ani_manager = {}
ani_manager.ids = {
    combat = {
        medium_s = {
            "ids are here",
            "ids are here"
        },
        light_s = {},
        heavy_s = {}
    },
    casual = {
        idle = "",
        confirm = "",
        deny = ""
    }
}

function ani_manager.GetAnimationArray(AnimationId, OverridingTable)
    local cycling_table = OverridingTable or ani_manager.ids
    for index, array in pairs(cycling_table) do
        if index == AnimationId then
            return array
        elseif type(array) == "table" then
            local Result = ani_manager.GetAnimationArray(AnimationId, array)
			if type(Result) == "table" then
				return Result
			end
        end
    end
    return nil
end

print(ani_manager.GetAnimationArray("medium_s"))  -- {[1] = "ids are here", [2] = "ids are here"}

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.