Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
COMMUNITY QUESTION

Is it possible to make an iterator in Lua that can iterate over a dictionary?

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.

3 comments

0

I would say that it is possible, but complicated.

0

I am still working on trying to find out an answer myself; If i find out an answer I will be sure to answer my won question.

0

I don't understand your question but, I'm positively sure that I'd be able to help you with your answer. My confidence comes from experience with dictionaries.

1 answer

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.

This discussion is preserved as it was. New answers, comments, and votes are closed.