How to convert a tree of instances to a table?

Hello devforum, I’ve been dying to figure this out. Let me explain:
I have a way to convert a table to a tree of instances, but how do I do the opposite? To give you an idea of what I’m struggling with here’s what it looks like converting a table to a tree of instances:

local function createData(data, parent)
	for index, value in pairs(data) do
		if typeof(value) == "table" then
			local folder = Instance.new("Folder")
			folder.Name = index
			folder.Parent = parent
			createData(value, folder)
		end
		
		if typeof(value) == "string" then
			local stringValue = Instance.new("StringValue")
			stringValue.Name = index
			stringValue.Value = value
			stringValue.Parent = parent
		end
		
		if typeof(value) == "boolean" then
			local boolValue = Instance.new("BoolValue")
			boolValue.Name = index
			boolValue.Value = value
			boolValue.Parent = parent
		end
		
		if typeof(value) == "number" then
			local boolValue = Instance.new("NumberValue")
			boolValue.Name = index
			boolValue.Value = value
			boolValue.Parent = parent
		end
	end
end

The other topic only shows how to create one layer of children, I want a way to do this infinitely.

You can use GetDescendants() for this.

1 Like

Okay, it’s understandable that you didn’t comprehend what I was asking because I didn’t explain this very well. I’ll make this more visual:

I already turned this:

{
	Cosmetics = {
		RocketLauncher = {
			"Default"
		};
		Slingshot = {
			"Default"
		};
		Superball = {
			"Default"
		};
		Sword = {
			"Default"
		};
		TimeBomb = {
			"Default"
		};
		Trowel = {
			"Default"
		};
	};
	
	Equipped = {
		RocketLauncher = "Default";
		Slingshot = "Default";
		Superball = "Default";
		Sword = "Default";
		TimeBomb = "Default";
		Trowel = "Default";
	}	
}

Into this:
image

But how do I turn that: (^)

Back into this?

{
	Cosmetics = {
		RocketLauncher = {
			"Default"
		};
		Slingshot = {
			"Default"
		};
		Superball = {
			"Default"
		};
		Sword = {
			"Default"
		};
		TimeBomb = {
			"Default"
		};
		Trowel = {
			"Default"
		};
	};
	
	Equipped = {
		RocketLauncher = "Default";
		Slingshot = "Default";
		Superball = "Default";
		Sword = "Default";
		TimeBomb = "Default";
		Trowel = "Default";
	}	
}

You first use GetDescendants() which returns a table of instances. Then use a for loop to iterate through all the instances to create tables with the the information (table.insert() will help)

1 Like

That’s not very specific, I have a general idea of what to do, but I don’t know specifically what to do.

To elaborate, when I was writing the code I didn’t know how to keep the hierarchy of the table within the instance. I want a way to keep the hierarchy of the folder.

Hi there!

I use an open source module for accomplishing a similar goal as listed here. Check it out! https://www.roblox.com/library/590549414/OAuth2-Table-Module

One gotcha: It does not handle booleans. My workaround is to use intvalues and 0/1. If this doesn’t work for you, sorry about that!

Its pretty easy to reverse it using the function you provided. Since the function operates recursively you can go as deep as you want into it. Really all you need to do is switch the arguments in the if statements with what you are creating in the if statements. So essentially it would be like this

local function createData(datafolder,datatable)
		-- we will create a new table to hold the data
		for index, value in pairs(datafolder:GetChildren()) do
		if value:IsA("Folder") then
			local t = {} -- this table represents the folder
			-- since you had it that the index in the original table was the name of the value we will put the values in the table at the index which is their name
			datatable[value.Name] = t
			-- do the recursion
			createData(value,t)
		end
		-- since the type of the value doesn't matter when were inserting it we can just use on if statement
		-- we can determine if a instance value is a value by checking if it has a .Value property and not a child named "Value"(ik its kind of hacky but i dont want to type our like 3 more ifstatements)
		if value["Value"] and not value:FindFirstChild("Value") then
			datatable[value.Name] = value.Value
		end 
	end
end
2 Likes

You essentially want to do the exact opposite of what you’re doing. That is, something like this:

local function instanceToTree(obj)
  local tree = {}
  for _, v in ipairs(obj:GetChildren()) do
    if v:IsA("Folder") then
      tree[v.Name] = {}
   elseif v:IsA("StringValue") then
     tree[v.Name] = v.Value
  elseif v:IsA("NumberValue") then
     -- And so on
  end
  return tree
end

There’s an obvious problem to solve though: that only handles the root of the Instance, which isn’t good enough. It also doesn’t account for when you want an array (though at this point I’d like to take a moment and ask you if you think this is a good idea; how do you tell whether you mean the key 1 or the key “1”?).

The easiest way to handle the first issue would be with recursion, which you already have in the OP. The easiest way I can think of to implement this is something like this:

local function instanceToTree(obj)
  local tree = {}
  for _, v in ipairs(obj:GetChildren()) do
    if v:IsA("Folder") then
      tree[v.Name] = instanceToTree(v) -- This ensures that whenever a folder shows up, it and its children get added
   elseif v:IsA("StringValue") then
     tree[v.Name] = v.Value
  elseif v:IsA("NumberValue") then
     -- And so on
  end
  return tree
end

There’s a better way to do this which @wafflecow321 touched on in his code snippet where you can actually just put all Value objects in their own branch of the if-statement. Rather than doing what he did though, I would check if an object is a ValueBase, which all Value objects inherit from. You can do that with v:IsA("ValueBase") but I’ll leave the full implementation to you if you want to experiment with it.

For the sake of brevity I’m also not touching on how to check for arrays, since that’s simple enough. I just wanted you to think about that while implementing this.

1 Like

I wish I knew about ValueBase before lol. Is there a source of information where you can get superclass names for things like values? In the Roblox Dev Hub theres a class tree but it doesnt show base classes like ValueBase.

I believe that’s because ValueBase is just an empty identifier superclass. No ValueObject actually inherits from it if you check their pages and the ValueBase class doesn’t have any items common to a ValueObject, given that each Value’s use case is unique and all other properties are either unique to that type of ValueObject or just inherited from Instance.

You can request for its addition to the Class Tree via the Developer Hub category in Platform Feedback.

1 Like

I tend to use a site Anaminus hosts, Roblox API Reference. It’s automatically generated from the API dump so it’s as up to date as anything can be. It’s super helpful for when you need more esoteric knowledge of the API like what super classes something has.

It’s a bit of a shame that this info isn’t on the devhub, though I suppose some things inevitably get lost. Like Colbert said, I encourage you to make a documentation request for ValueBase at the very least since it can save people a lot of grief.