Detecting Type of Table (Empty, Array, Dictionary, MixedTable)

I’m not sure if this would work perfectly in most if not all conditions so I decided to ask you guys to have a look for me.

What would you classify {nil, nil, 3} as? Would it be an array, a mixed table, or both?

Special Array with Gaps, since it’s not structured like a Dictionary and you Index them with numbers not strings or anything else.

Dictionaries can’t have nil as a key or value anyways, in this case MixedTables are Arrays combined with Dictionaries.

Here’s something to throw you off, then. a is a dictionary but b is an array. When you iterate them, you wouldn’t be able to tell them apart.

local a = {[3] = 3} -- you index this with numbers, but it's a Dictionary
local b = {nil, nil, 3} -- ditto, but it's an Array now.
print(IsEmpty(a), IsArray(a), IsDictionary(a), IsMixedTable(a))
print(IsEmpty(b), IsArray(b), IsDictionary(b), IsMixedTable(b))
false false Dictionary Dictionary
false Array false Array

While writing the code above I used this thread as a reference.

Am I misunderstanding something, aren’t those functions working fine?

How about one that’s not any of the above :^)

local a = {[1] = 1, [2] = 2, [3] = 3}
a[2] = nil
print(IsEmpty(a), IsArray(a), IsDictionary(a), IsMixedTable(a))
false false false false

I think the only fool-proof way to check if something is an array, a dictionary, or mixed is to iterate through everything.

local a = {[1] = 1, [2] = 2, [3] = 3}
print(IsMixedTable(a))
print(IsEmpty(a), IsArray(a), IsDictionary(a), IsMixedTable(a))

I got this from my output

Array

false Array false Array

You’re missing the part where I set a[2] to nil.

EDIT: Unrelated to table shennanigans, but you named your functions Is____. One would expect these functions to return booleans, not a string or nil.

Right, my bad.

So how do I improve my code?



I’m using IsMixedTable(a) to call all of the other functions to get the type otherwise it will return false anyways if it’s not a string, so it’s the same for me whatever it returns

if IsArray(a) then

end

if IsMixedTable(a) == "Type" then

end

As a matter of style, you should just have a function that returns one of four mutually exclusive values: { "Empty", "Array", "Dictionary", "MixedTable" }, and your Is___ functions should just do a simple equality check.

local function getTableType(t)
    -- returns one of { "Empty", "Array", "Dictionary", "Mixed" }
end

local function isEmpty(t)
    return getTableType(t) == "Empty"
end

local function isArray(t)
    return getTableType(t) == "Array"
end

local function isDictionary(t)
    return getTableType(t) == "Dictionary"
end 

local function isMixed(t)
    return getTableType(t) == "Mixed"
end

There’s also the issue of how you define an array. You say that {nil, nil, 3} would be classified as an array, but the wiki would beg to differ:

Would {nil, nil, 3} still be classified as an array (against established convention) or would it be its own class?

so what would it be classified as?

and how can I fixed my code’s flaw, ignore the style, I want the code to have a flawless functionality

However, wouldn’t it be a rare case to have a Table structured like one of your examples?

Most of the time I structure my Tables to be Remote and Datastore compatible but in those rare cases like that I have ways to handle them

Style is entirely relevant to the code review, since (one of the) goals of code review is to improve code quality, and style is part of that.

If you only cared about whether or not it functions properly, then you’re probably better off asking “How would I classify a table as empty, array, etc…” in scripting support.

Maybe? I don’t know how the code will be used. Something like that is pretty subjective. Besides, all this means is that the code is rarely wrong, and that’s not exactly “flawless functionality”.

EDIT: What do you plan on using this code on anyway? There are probably better solutions to the problem you’re trying to solve.

I don’t think brushing off edge cases as “rare” makes your code more correct. It misidentifies a certain case.

If you’re now changing the question from “does my code work flawlessly?” to “does my code work flawlessly with my specific uses and nothing else?” then you’ll need to supply examples of every style of table you plan to put through it.

You asked for flawless functionality. Failed cases, regardless of how rare, is not flawless.

1 Like

Yeah, I moved it to Code Review, my mistake

Checking the type of a Table, I want to make sure that it gives me the correct result while Debugging.
(I’m only asking you to ignore the style because it’s less important right now)

That’s why I’m asking how I can improve the functionality because I know it’s not flawless, that’s the point of the Thread, I’m only mentioning what I said as a question to gather more insight nothing more than that, I’m not saying that my code is correct but rather that I’m willing to improve it so in that rare case it works flawlessly and understand when that rare casewould occur.

If we stick by your original definition of by-the-docs arrays with nil keys being classified as arrays, then classification is pretty easy:

1. If next(t) is nil, then it is empty.
2. Iterate through *every* key with next().
   * If we only encounter positive integers, then it must be an array (again, according to your definition).
   * If we only encounter non-integers or non-positive integers, then it must be a dictionary.
   * Otherwise, it is mixed.

Here’s the steps in lua:

local function getTableType(t)
    if next(t) == nil then return "Empty" end
    local isArray = true
    local isDictionary = true
    for k, _ in next, t do
        if typeof(k) == "number" and k%1 == 0 and k > 0 then
            isDictionary = false
        else
            isArray = false
        end
    end
    if isArray then
        return "Array"
    elseif isDictionary then
        return "Dictionary"
    else
        return "Mixed"
    end
end

The curveballs I showed you:

local a = {[1] = 1, [2] = 2, [3] = 3}
a[2] = nil
local b = {[3] = 3}
local c = {nil, nil, 3}

print(getTableType(a))
print(getTableType(b))
print(getTableType(c))

prints what you’d expect:

Array
Array
Array

Your original 4 test cases also pass this:

print(getTableType({}),getTableType({1}),getTableType({John = true}),getTableType({1,John = true}))
Empty Array Dictionary Mixed
6 Likes

Thanks, this is exactly what I need!



I’m wondering if my Definition of arrays

is that bad or it’s fine?

I really don’t mind extra details, I like learning

I really don’t know, but personally I wouldn’t classify them as an array at all. Besides, the only case (in Roblox, that I could think of, at least) where this sort of distinction really even matters is when you’re trying to serialize data using JSONEncode (and, by proxy, whenever you want to store stuff in a DataStore) since you can’t serialize mixed tables correctly. and even then, JSONEncode acts weird with the curveballs I showed you:

local HttpService = game:GetService("HttpService") 
local t = {1, 2 ,3}
t[2] = nil 
local enc = HttpService:JSONEncode(t)
print(#t, enc)
t = {[1] = 1, [3] = 3}
local enc = HttpService:JSONEncode(t)
print(#t, enc)

prints:

3 [1,null,3]
1 [1]

Tables are weird.

2 Likes