Lets say that I have a dictionary in Lua (i.e. a Lua table that contains indexes of type string) like so:
local my_dictionary = {a = 123; b = 321; c = 456; d = 654};
What I am trying to do is create an iterator function that can iterate over a table even if its indexes are of type string; kind of like pairs, however whenever I try to call next() to get the next index,value it will only return the index,value if the index is of type int. An idea I had was maybe to call (index):byte(1, -1) and add up the tuple of ints, and use that as a sort of pretend index, just to keep track of the indexes, but I do not think that would work with next. Here is basically what I have so far:
local function each(list) if #list > 0 then local function my_itr(lst, ind) return next(lst, ind); end return my_itr, List, 0; end return function() end, nil, nil; end
this only works for a table with int indexes (an array table), so I was wondering if anyone could help me out. Thanks.
I have figured out the answer to my own question:
In short, the answer is yes
However it is a fairly complicated process that you the creator must code to iterate through the dictionary to your liking.
In my case, I simply wanted to create an iterator that could iterate through a dictionary, or a table with string indexes. I did not care, as long as it would iterate through each and every index; regardless of the index's type.
You will not understand how thankful you should really be that Lua has the function next until you have written out your own dictionary iterator as well; with that being said I will get to the code portion of this:
I created two functions, ItrConvertTableToArray is a function that will convert a table (which could have int and string indexes) to an array (which will only have int indexes)
local function ItrConvertTableToArray(List) local int_indexes = {}; local str_indexes = {}; for i = 1, #List do int_indexes[#int_indexes + 1] = { index = i; org_index = i; value = List[i]}; end local first = true; local current_str_index; for i,v in next,List do if type(i) == stg then if first then first = false; local max_int_indexes = #int_indexes; current_str_index = max_int_indexes + 1; else current_str_index = current_str_index + 1; end str_indexes[#str_indexes + 1] = { index = current_str_index; org_index = i; value = v}; end end local array = {}; for i = 1, #int_indexes do array[#array + 1] = int_indexes[i]; end for i = 1, #str_indexes do array[#array + 1] = str_indexes[i]; end return array; end function each(List) if type(List) == "table" then local lst = ItrConvertTableToArray(List); local function itr(t, ind) ind = ind + 1; val = t[ind]; if val == nil then return nil; end return val.index, val.org_index, val.value; end return itr, lst, 0; end return function() end, nil, nil; end
The iterator function each is actually a very simple one; in fact it works almost exactly like ipairs does. The complicated part is the ItrConvertTableToArray function (or the function that converts the table to an array), depending on how you want the indexes to be ordered it can get fairly complicated; you would have to come up with your own way of ordering every string and int key together. Because i had no preference, I simply looped through all of the int indexes in order, and stored their keys and values, then I used the next function to actually go through all of the string indexes; if it weren't for next, I would have to code SO much more preparations before even getting to this point. In my case when i return the array, I am able to continue the each iterator function similar to the ipairs iterator structure.
In the end, each makes for a nice, clean generic for loop:
local my_data = { a = 123; b = "321"; c = true; 1, 2, 3, 4, 5, "abc", true, false, abcdef = function() end; }; for i,k,v in each(my_data) do print(i,k,v); end
:1 1 1
:2 2 2
:3 3 3
:4 4 4
:5 5 5
:6 6 abc
:7 7 true
:8 8 false
:9 a 123
:10 b 321
:11 c true
:12 abcdef function: [hex_value]
i is index of the element inside of the array that we created in order to iterate the table, k is the actual index of the value inside the original table (in this case my_data), and v is the value the the index k points to inside of the original table.