Referencing a Dictionary through a table

sorry about the weird title, I kept getting “title isn’t a complete sentence” message and couldn’t find a way to re-word what I was going to put without the error message

Ok this is a quick question, basically I have a dictionary, that looks something like this:

local Dictionary = {
["Item1"] = 0,
["ItemType"] = {["Item1"] = 0, ["Item2"] = 0},
["ItemType2"] = {["SubItemType1"] = {["Item1"] = 0, ["Item2"] = 0}, ["SubItemType2"] = {} 
-- ... etc
}

I’m creating a function to be able to write to the dictionary, and I’m trying to just make it look cleaner. Here’s what my idea was:

I’m passing in 2 values,

  1. Path (The path to the value I want to be written to)
    This is a table that would look something like this:
    {“ItemType2”, “SubItemType1”, “Item1”}

  2. Value (The value that is written to the given path.)
    This is just a number

The goal is to sort of have something like this:

Dictionary[Path[1]][Path[2]][Path[3]] = Value

Well, the problem with this is the length of the path will be different at times. If I want Dictionary[“Item1”] to be written to I’d need it to be:

Dictionary[Path[1]] = value

However, I don’t know how to do this without having the ugly:

if #Path == 1 then
   Dictionary[Path[1]] = value
elseif #Path == 2 then
   Dictionary[Path[1]][Path[2]] = value
elseif #Path == 3 then
   Dictionary[Path[1]][Path[2]][Path[3]] = Value
end

This looks like something that could/should be shortened but I’m not quite sure how.

1 Like

Not sure if I’m understanding correctly but why why not create a nested table for different items, and then different tables for different ItemTypes? You can also reference the different tables by declaring the variables at the top, then assigning them values later.

local items, itemTypes, subItemTypes
items = {
    ['Item1'] = {
        ['ItemType'] = 1; -- or you can do ['ItemType'] = itemTypes[1]
        ['SubItemType'] = 2; -- same here, ['SubItemType'] = subItemTypes[2]
    };
}
itemTypes = {
    [1] = 'Sword';
    [2] = 'Axe';
}
subItemTypes = {
    [1] = 'Dull';
    [2] = 'Sharp';
}

“itemType” and “SubItemType” were just placeholders, The specific case I’m currently using it in is a save system where it looks like this:

local StartData = {
	["Version"] = 0,
	["Collectables"] = {["Cash"] = 0, ["Medals"] = 0},
	["Cosmetics"] = {["Titles"] = {}},
	["Selected"] = 0,
	["Stage"] = 0,
	["Levels"] = {
		["0"] = {["Completed"] = false, ["Selected"] = true, ["Medals"] = {}},
	},
	["PlayerInformation"] = {["Suspicious"] = false, ["TriggerdTypes"] = {}, ["Warns"] = 0, ["Banned"] = false, ["Hidden"] = false},
}

I’m passing in the Path and Value from a BindableEvent so It can be added to the dictionary for the next auto Save.

1 Like

Ah, got it. Thanks for that. I’m a little confused as to where you’re having the values reference each other though? You should be able to edit values externally like this:

StartData['Levels']['0']['Completed'] = true
1 Like

Well, the problem is I’m sending information through a bindable event.

I would prefer to just send {“Levels”, “0”, “Completed”} and somehow be able to reference the dictionary from that.

I wouldn’t be able to do this because

[Path[1]][Path[2]][Path[3]] 

ignores the case where the path is only 1 or 2 long. ({“Collectables”, “Cash”})

1 Like

I’m not sure why you need it like this, but you can use something like this to traverse to an arbitrary Path depth/length:

local function readPath(Dictionary, Path)
    for _, v in ipairs(Path) do
        if Dictionary[v] then
            Dictionary = Dictionary[v]
        else
            return Dictionary, v .. " is not a valid child of " .. Dictionary.Name -- or some other property!
        end
    end
    return Dictionary
end
2 Likes

Yea this is something I’ve tried:

   local currentPath = PlayersData[key]
	for i = 1, #Path do
		currentPath = currentPath[Path[i]]
	end
	print(currentPath) -- nil
	print(Value) -- 0
	currentPath = Value
	print(currentPath) -- 0
end

However it doesn’t seem write to the dictionary, it seems to just overwrite the variable.

1 Like

That’s why you use a function! (or a do block with a temp value to hold the reference)

What you’ve essentially created is a form of Linked List, so you need to either intentionally shadow the variable in a function, as I did, or create a second variable so you can have both references at once.

EDIT 2: Oh, I misread what you did there. If you’re overwriting the final currentPath[Path[i]] with a value, you have to do that, you can’t set currentPath to the value, it’s the same as trying to do v = a.property; v = 10; --a.property is unchanged

Example:

local function setPath(Dictionary, Path, Value)
	for i = 1, #Path - 1 do
        local v  = Path[i]
		if Dictionary[v] then
			Dictionary = Dictionary[v]
		else
			return false, v .. " is not a valid child of " .. Dictionary.Name -- or some other property!
		end
	end
	Dictionary[Path[#Path]] = Value
	return true
end
3 Likes

Thanks, it worked properly!

I remembered from a while back that dictionaries were passed by reference and not value. Which is why I thought it’d work, though I must’ve forgotten that setting a variable = to a Non-dictionary Value in the dictionary would instead pass the value.

Thank you for teaching me something new!