Finding the number of key in a dictionary?

Hello! I’m having trouble finding an easy answer for this, and i’ve searched for one, but i can’t find any specific answers. Could just be asking the wrong question… but, how would I go about retrieving the number of a key in a dictionary when the key is a string value, and this would need to be doable in a layered dictionary with dictionaries in dictionaries.
for instance:
dictionary = {
[“Dog”] = { --I want to find the number of this key here which would be 1.
[“Dog’s snout”] = true,
},
[“Cat”] = {
[“Cat’s tail”] = true,
}
}

My reasoning for needing this is for deserialization, so i need to be able to retrieve the key’s number to match it with an keyid that’s serialized and saved in a datastore, so i wouldn’t necessarily know that i’m looking for “Dog”

I’d need to loop through, and discover the key’s order in side each dictionary, and match with the datastore.

This is a physical example of the code i’m using (which i’m using the Datastore2 module)
image

Basically, previously, when the game loaded, i looped through the actual default data value dictionary to get all the names of the values and put them in a seperate key dictionary for later comparison with the deserialized key ids. The circled part is where I would loop through the inside table loaded in the dictionary. But again, to be clear i need to find the number order value of ‘i’ which in this case will instead give me a string name of whatever item i’m fetching.

In some of the other stores, i only need to save one dictionary, so i dont have to go the extra mile by creating nested dictionaries. But this one i do. WIth the other tables that are created. In the other more basic stores, the for loop will detect ‘i’ as the key’s number since it does not have a value of a table, but in this more complex one, the for loop will detect ‘i’ as the name of the table instead of the key’s order. So i need to find the number of the key without getting the name.

i’m wondering if i can do three variables then? like
for num,i,v in pairs(dictionary) do
end

?
would that work?

I don’t know. Any help would be much appreciated. Thankyou for reading! :smiley:
-Manelin

2 Likes

From your brief first example, no, you can’t do this. Dictionaries don’t hold any order, so they don’t have a numeric key index. You can store one yourself as a hard coded value if you want.

Also on a separate note…

for i, v in pairs(Dict) do
    if i == something then
        -- code
    end
end

Can be shortened to:

local v = Dict[something]

if v then
    -- code
end

Although I’m not sure if this was your intended behavior to begin with.

2 Likes

Thank you for your speedy response. I appreciate it. Any solutions or idea to achieve what i’m trying to would be mightily useful! :smiley:

You provided this example; if you wanted to have an ID with each item you could manually add them.
Example:

{
    ["Dog"] = {
        ["ID"] = 1,
        ["Dog's snout"] = true,
    }
}

When iterating, you could then read the ID via v.ID and such. You can alternatively use an array and keep the name inside if you want to do by-ID lookups.

{
    { -- at index/ID 1
        ["Name"] = "Dog",
        ["Dog's snout"] = true,
    }
}

But it depends on your use case.

Pertaining to your three variables question, no, you cannot do this.

Like already stated above, Lua dictionaries don’t hold some sort of order, so you cannot access a key unless you add some sort of key that holds the index already. The only problem with this is that if you want to add new entries, you’re gonna have to update the key ID for every new entry you make. Works fine if you’re planning on your system have only a few entries, but that’s not very good if you’re planning on having like 1000 entries per say.

Would it possibly work if you instead didn’t even make your inner table a dictionary at all? Maybe possibly rethink your design approach? This also seems like it could be solved with a little OOP (Object Oriented Programming) for organization purposes.

And theres no way of looping through a dictionary in order?

Maybe in next? Instead of in pairs?

pairs just returns next, there is no different behavior. The only difference is that the former is idiomatically correct, and you call it yourself to get next.

A table’s dictionary part has no ordering, it simply “maps” keys to values.

Like suggested by Autterfly if you really need an ordered dictionary you would make an array of dictionaries with a single key-value pair. But I would do it a little different since the keys can vary.

local t = {
    { key = "k", value = "v" },
    { key = "other_k", value = "other_v" }
    { key = "a", value = 0 },
    { key = "b", value = 1 }
}

for _, pair in ipairs(t) do
    print(pair.key, "=", pair.value)
end

So does looping through a dictionary do a random order every time or is there at all a method to the jumbled madness?

The order of the keys in a dictionary is not guaranteed. It may be in the same order and sometimes it might not be.

My suggestion would be to add a number to the value of each key indicating the order you want them to be in. Then when you need to get them in a certain order just iterate through all of the keys until you find the “index” that you want. That’s probably the only thing you can do to reliably get the functionality you want

You can use ipairs().

ipairs (table): The ipairs () function will allow iteration over index-value pairs. These are key-value pairs where the keys are indices into an array. The order in which elements are returned is guaranteed to be in the numeric order of the indices, and non-integer keys are simply skipped.


pairs() and ipairs() are slightly different as well.

  • pairs() returns key-value pairs and is mostly used for associative tables. key order is unspecified.
  • ipairs() returns index-value pairs and is mostly used for numeric tables. Non numeric keys in an array are ignored, while the index order is deterministic (in numeric order).

Yes but, ipairs() can’t exactly be used to traverse a non-numerically indexed table in the first place - nor does it index non-list items. Unless your proposal is to convert the dictionary into an array somehow.

@Manelin

The number of keys in a dictionary can be found by just looping in pairs through one, and incrementing a variable after every iteration.

If the maximum amount of tables that can be within the dictionary associated with a key is 1; then something like this would work (could be adjusted to be recursive too, to work with multiple tables within tables)

based on what I think you're asking

 local dictionary = {
 
   ["What Snout"] = {

           ["Snout"] = "dog";
           ["cat"] = true;
           ["metasynctatic"] = false;
                           
                    };

   ["more snouts"] = {
                          "non nil";
                          "snout";
                           false;
                                    }
 }
 
  local count = 0
  for key, value in pairs(dictionary) do
           if typeof(value) == "table" then  
              for _, v in pairs(value) do 
              count = count + 1
              end
           end
  count = count + 1

  end
       
 print(count)

Dictionaries are stored as hash tables, there’s no certain order for the hashing algorithm .

@Elocore’s suggestion could work, if that is the functionality you want.