How to use ipairs on dictionaries

just a note here, this solution will work well, but it depends on the table you are working with

examples:

this works
{
	["abc"] = 5000,
	["def"] = 15000,
	["ghi"] = 35000,
	["jkl"] = 50000,
	["mno"] = 75000
}
{
	["1"] = 5000,
	["2"] = 15000,
	["3"] = 35000,
	["4"] = 50000,
	["5"] = 75000
}
this doesn't work
{
	["How"] = 5000,
	["Are"] = 15000,
	["You"] = 35000,
	["Today"] = 50000,
	["?"] = 75000
}
{
	["1"] = 5000,
	["2"] = 15000,
	[3] = 35000,
	["4"] = 50000,
	["5"] = 75000
}
{
	[true] = 5000,
	[false] = 15000
}

you might be wondering, why doesn’t this work with all dictionaries?
well the function sorts alphanumerically, this means that it will work if the number keys are in order or if the text is in alphabetical order

you also can’t have a string and a number as a key in the same table, this is because you can’t compare string and number

anyways since it sorts alphanumerically stuff like this also won’t work right

more stuff that doesn't work
{
	["5"] = 5000,
	["4"] = 15000,
	["3"] = 35000,
	["2"] = 50000,
	["1"] = 75000
}
{
	["mno"] = 5000,
	["jkl"] = 15000,
	["ghi"] = 35000,
	["def"] = 50000,
	["abc"] = 75000
}
{
	["One"] = 5000,
	["1"] = 15000,
	["Two"] = 35000,
	["2"] = 50000
}

hope some find this reply a bit helpful

1 Like

I slightly modified a code sample I wrote a few months ago, for your specific situation:

local dictionary = { -- the dictionary in question to be looped through
   -- these are example values to be sorted properly
   ['110'] = 100011001,
   ['105'] = 20293922,
   ['230'] = 923929932,
   ['c'] = 292382,
   ['a'] = 29382393128,
}

local function loopDictionaryInOrder(dict, func)
  local data = {} -- array to hold the indexes

  for key, value in pairs(dict) do -- loops though the dictionary provided in the first parameter
    table.insert(data, key) -- this adds each key to the 'data' array
  end

  table.sort(data, function(a, b) -- this sorts the data array by each key's byte (numeric representations)
    local toNumA = tonumber(a)
    local toNumB = tonumber(b)

    if toNumA and toNumB then
     -- this checks for 2 integer values and sorts them accordingly
     return toNumA < toNumB
    end

    return tostring(a):lower():byte() < tostring(b):lower():byte()
  end)

  for _, key in ipairs(data) do 
     -- loops through the 'data' array and calls the function provided in the second parameter
     -- the function gives the key as the first argument and the key's value as the second argument
    func(key, dict[key])
  end
end

-- this is an example usage of the function
loopDictionaryInOrder(dictionary, function(key, value)
   -- print each key and value in order
   print(key, value)
end)

I can’t see if this works in Roblox Studio because Roblox is down at the moment, but it works on Lua’s Demo Site.

1 Like

The regular sort provides the same result in this case.
You could also use the function as an iterator function, which I think is pretty cool:

local function idict(t)
    local keys = {}
    for k in next, t do
        table.insert(keys, k)
    end
    table.sort(keys)
    return function(_, i)
        i += 1
        local k = keys[i]
        if k then
            return i, k, t[k]
        end
    end, keys, 0
end

for _, k, v in idict(module.healths) do
    print(k, v)
end
1 Like

you can easily fix this using tostring() in the second argument for table.sort()

table.sort(Table, function(a, b)
    return tostring(a) < tostring(b)
end)

now the sorting shouldn’t error like it did before, though like I said it doesn’t sort correctly with every table

1 Like

Thank you very much for all your replies! I should have edited the title, but what I actually want is a function that returns the next index of the given index. Can someone help me with making a function that returns the next index of a given index please? Like for example,

module.NextHealth = function(currentHealth)
    -- current health is 145
    -- I want to get 160 because it is the next index
    -- if currentHealth is already the last index, return the string "MAX"
end

Thank you so much for helping me!

For dictionaries, that works like this.

local nextIndex, nextValue = next(table, currentIndex)

Bear in mind, as I’ve mentioned, that dictionaries don’t really have an order. I think this method does work on arrays and in order, but if it doesn’t then this is all you need.

local function arrayNext(tab, key)
    return key+1, tab[key+1] or "MAX"
end

For the next index function in dictionary, can you help me turn it into a function that returns the next index please? Thank you so much!

Unless one of us is confused here, that’s what the first code I posted there will do. Let me know if you need it to do something different.

Its worh noting that Lua cannot guarantee the order of a dictionary that doesn’t have a numeric key sequence. ipairs internally runs through an array from 1 until it hits a nil value.

Since dictionaries dont have a numeric key sequence, it simply cannot work. The only way to do this is to sort the dictionary into a list of key value pairs yourself by passing through it, then ipairs it
{["110"] = "metatablecatgirl"} -> {[1] = {Key = "110", Value = "metatablecatgirl"}}

how do I do it? Can you give me a function that returns the next index of the index i give?

I mean that’s literally the code I gave.
If you want to get the next index and value in a dictionary you can use this

local nextIndex, nextValue = next(table, currentIndex)

So by way of example

local example = {Boat = "Red", Car = "Blue", Truck = "Green"}
local nextIndex, nextValue = next(example, "Car")
print(nextIndex)
print(nextValue)

This will print the index and value after the index “Car”. I really don’t think this is what you want though since you seem to want your dictionary to be ordered. I think you need to refer to my first post in this thread.

module.healths = {
	["100"] = 5000;
	["110"] = 15000;
	["120"] = 35000;
	["130"] = 50000;
	["145"] = 75000;
	["160"] = 125000;
	["185"] = 300000;
	["200"] = 475000;
	["225"] = 750000;
	["255"] = 1050000;
	["280"] = 1350000;
	["320"] = 1850000;
}
module.healthsIndex = {}
for key, value in pairs(module.healths) do
    module.healthsIndex[#module.healthsIndex+1] = key
end
table.sort(module.healthsIndex, function(a, b) return module.healths[a] < module.healths[b] end) -- Sort by value rather than key

module.healthsNext = function(key)
    local index = table.find(module.healthsIndex, key)
    if index then
        local newKey = module.healthsIndex[index+1]
        if key then return newKey, module.healths[newKey]
        else return "NaN", "MAX" end -- If there is nothing larger, return the key NaN and the value MAX
    else
        warn(("Unable to find key \"%s\" in module.healthsIndex"):format(key))
    end
end

print(module.healthsNext("120")) --> 130, 50000

wow thank you so much bro i never new it was that easy!!! Sorry for the confusion but i never knew about the next() function so I made a REALLY COMPLICATED way of using an odered loop to get the next index thanks

just a tip, table.insert is faster performance wise
so I would switch it for this

table.insert(module.healthsIndex, key)

besides table.insert is made for this anyways

Oh shoot I forgot. I kept thinking table.insert was slower just because it shifted all the table entries when you inserted in the middle of the table. But it’s written in C innit?

yea it should be written in C, also roblox mods confirmed it was faster as well

“rawset , rawget , rawequal and 2-argument table.insert are now 40-50% faster; notably, table.insert(t, v) is now faster than t[#t+1]=v”

you should be able to find that quote under performance improvements
I had to quote it like this because the topic is closed and I can’t exactly quote it from there so a hyperlink will work

1 Like

Sorry, I removed the solution mark because the next() functions returns nil. Can you please help? Here is the topic: Next() not working - #11 by John_15051