Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
0

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

Asked by
movsb 242 Moderation Voter
6 years ago

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.

0
I would say that it is possible, but complicated. Kulh 125 — 6y
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. movsb 242 — 6y
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. KingLoneCat 2642 — 6y

1 answer

Log in to vote
0
Answered by
movsb 242 Moderation Voter
6 years ago

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.

Ad

Answer this question