How can I use in pairs?

@InternallyAmplified GetChildren() returns an array, not a table.
Edit: an array is a type of table.


In pairs is normally used for loops considering an objects children. A child is basically something that is under an object.

pairs is basically a simplified function that tells the script what to do, pairs is almost the same as doing this:

function pairs(Table)
    for i = 1, #Table do
         return i, Table[i] -- "i" is the index while "Table[i]" is the object corresponding to the index
    end
end

This is what pairs could be used for:

for i, v in pairs(workspace:GetDescendants()) do -- "i" is the "i" and "v" is the "Table[i]"
    v.Name = i -- Makes the name of the object the index
end

Index is the numeric value of something: 1, 2, 3, 4, etc.


Replying to @xNick_O’s post below:

pretend I have a table:

local Table = {"a", "b", "c". "d"}

Then I do:

print(Table[4])

It will print "d".

I was just the index, so if I were to loop through that table with the index:

for i = 1, #Table do
    print(Table[i]) -- prints "a", then "b", then "c", then "d"
end

The Number sign # is just to tell how many things are in a table or array.

2 Likes

Why do you put a number sign before Tab;e and those brackets by i?

1 Like

I know it returns an array, i am simplifying it for him because i assume he doesnt know what tables / arrays are.
Figuritavely speaking though, they’re both the same if you think about it:

Item:GetChildren() = {Item.Part1, Item.Part2 etc…} So that’s why i reffer to both of them as tables

also @xNick_O he puts the [x] after table, (x being a number) to make refference to the xth item in that table

Table = {“one”, “two”, “four”, “nine”}, Table[4] = “Nine”

1 Like

That’s only when iterating over numerical indices. pairs just returns the next iterator function, the index- be it numerical or a string along with the associated value, whatever variables you pass i.e i, v they contain the values returned.

Technically still a table though, the term ‘array’ is just by Roblox standards, a table with numerical indices.

https://www.lua.org/pil/7.3.html
https://www.lua.org/pil/4.3.5.html

My reply here should be good for reference : Question regarding looping - #6 by un1ND3X


pairs is very often used in the wrong situations, always use ipairs to iterate over contiguous arrays, unless you want to iterate in arbitrary order with negligible increased speed.

The example I used doesn’t matter if you use in pairs or ipairs

It won’t affect the outcome, but examples like these are what sprout incorrect usage of pairs, if you can iterate a tiny bit faster then why not??

1 Like

You can also use in pairs to use a function for multiple parts. For example, if you wanted multiple parts to kill a player, you could put all of them in a folder named “Kill Bricks”. You would then use “in pairs” to apply a kill function for all those parts.

local killparts = workspace:FindFirstChild("Kill Bricks")

for _, v in pairs(killparts:GetDescendants()) do --gets all descendants of the folder
    if v:IsA("BasePart") then --checks if the current object is a part (it could possibly be a model, and we don't want that)
        v.Touched:Connect(function(hit) --If any part inside the folder is touched
            local character = hit:FindFirstAncestorOfClass("Model")
            if character and character.Humanoid then
                character.Humanoid.Health = 0
            end
        end)
    end
end
1 Like

The example I used doesn’t matter if you use in pairs or ipairs

1 Like

If they both have the same outcome, then it doesn’t matter which one you use. Plenty of people I know would use in pairs for a function like that.

1 Like

Then they’re missing out on micro-optimization, unless they’re iterating over non-list items (a dictionary for example) in which case pairs is just supposed to be used.

From another post of mine:

Again, it’s clearly just clearly negligible difference , there shouldn’t be too much of a difference unless you’re using pairs for traversing a huge array and using the counter index.

A table and an array aren’t different datatypes, so

print(type({['Key'] = "value"}))
-- and
print(type({"value"}))
-- will both print 'table'
-- to check for a typical table, do

 local tab = {}
 if type(tab) == "table" and #tab ~= 0 then 
    print("array") 
    else 
    print("dictionary")
end

@Abysmallow all posts made before this explain its usage, that should be enough for concept. Just use it as an iterator to reduce the amount of code, when you need to perform multiple repetitive operations for multiple objects, for example.

1 Like

Ok, but I’m just trying to give him an example of using in pairs, not ipairs. Yes it’s faster, but he’s asking about in pairs

1 Like

I found this post a bit misleading, so I just want to correct a few misconceptions:

An array is just a type of table with numeric incremental (aka 1, 2, 3) indexes. I’m not sure this is a nitpick worth making, since it is still a table.

You really should not be using in pairs for looping through an instance’s children. ipairs is generally preferred for arrays, and GetChildren will always return an array. ipairs is preferred partially because it’s faster, but also because it makes it clear what type of indexes you’re going to be expecting within the loop.

That function will only return 1 and the first element of Table; return immediately stops a function. It also completely ignores the fact pairs will loop through non-numeric indexes, like in {["hey"] = "yo"}

GetDescendants also returns an array, so ipairs should also be used here. I’m also not sure how helpful "i" is the "i" is, since that wouldn’t have helped me at all as a beginner.

Indexes can be any type. You can even index a table with a table! For example:

local t = {}
t[t] = t -- the value of the table at the position which is itself would be itself

print(t[t][t] == t) --> true

(I’m sure this is just a typo)

I mean, technically, it prints d. The quotation marks just signify that it’s a string in the code, they don’t appear in the output

I found this a bit misleading, so this is just to clarify: for i = 1, #Table do will just make a loop run once for each item of the table. i is simply a number that goes up each time. Since Table is an array in this case, any number between 1 and its length is a valid index, since that’s the definition of an array. It’s not really looping through the table like ipairs or pairs are, though, it’s just counting up from 1 to the table’s length in a way that happens to be useful for indexxing an array. This is pretty nitpicky and doesn’t really make a difference, but I think the distinction is important because it helps show how for i = x, y, z can be useful in other scenarios too.

That only works for arrays, not all tables. It won’t count non-numeric indexes. For example, a table like {["hey"] = "yo"} would have a length of 0.

6 Likes

nil and NaN aren’t valid table keys.

local t = {}
t[nil] = 1 --> table index is nil
local t = {}
t[0/0] = 1 --> table index is NaN
4 Likes

Please don’t confuse others, it returns a table indexed by numeric keys. It’s still a table, don’t believe me? Use type(t), considering t is a table.

2 Likes

There’s such thing as a mixed table. This is not a very reliable check. typeof is also ridiculously slow, so I’d recommend type where possible. Also, please don’t edit in a reply that answers a reply further down in the thread, it breaks the continuity of the thread.

3 Likes

The typeof was just because I’m used to using that for validating Roblox-specific datatypes, type should be used here probably.

Obviously not reliable, that’s the reason why I said it would only work for defining ‘typical’ tables (where it is either a dictionary or an array, was only a quick edit to my post), for example using that algorithm it would print {} as a dictionary which it technically isn’t.

I left an extra end there by mistake

Anyways, since I don’t have access to Studio, I wrote this in Lua 5.3.5


local tab = {1, nil, 1}

local function nilfound(t)

local i = 0
for _, _ in pairs(t) do
    i = i + 1
end

if i - #tab ~= 0 then return true end

end

setmetatable(tab, {
    __tostring = function(self)
     if nilfound(self) then return "nil found, cannot perform operation" end 
     local indexes, result, numericalindex = {}, nil, nil
           for k, _  in pairs(self) do 
               if type(k) == "number" then numericalindex = true end
               if type(k) ~= "number" and numericalindex then return "mixed table" end
               table.insert(indexes, k)
           end 

           if #indexes == 0 then return "empty table" end
           
           if #self ~= #indexes then result = "dictionary" 
           else
               result = "array"    
           end
           
        return result
     end


})

print(tab) --> cannot perform operation

Edit:

+This code was optimized to work better for various cases.

Just adding this here: typeof was optimized in Luau

@ zeuxcg

Optimize typeof() to run ~6x faster. It used to be that type() was much faster than typeof() but they now should be more or less comparable.

1 Like

???

Where in my post does it say a table is not a valid type, or that an array and a table are different types?

I was only suggesting that saying
type(t)
would return anything different from what calling type(t) would return where t is either a table or array is incorrect.

I’m just saying even if it were an array, type(t) would still return “table” so I won’t say that’s a reliable check to differentiate between a numerically indexed table or a dictionary.

1 Like

Keep in mind that even this convoluted of a check will still consider local tab = {1, 2, nil, 3, [true] = "there"} an array, so there’s not an ideal way to check for this.

4 Likes

Considers almost every case possible, if the table contains nil then it’ll not do anything because it’s not any of the three, (for the nil part, I had to resort to the forum and an unexpectedly simple function).

1 Like

Hey i have a question, how i can get only one value, like

for i,v in pairs(script.Workspace:GetChildren()) do 
		if v:IsA("BasePart") then
			print(v.Name) -- but only get the name of the first value it found
		end
1 Like

Iterating isn’t always necessary, ::GetChildren() returns an array, so just use the first returned object

local firstPart = workspace:GetChildren()[1]
if firstPart:IsA("BasePart") then 
    print(firstPart.Name) 
end

But if you want it to keep iterating until a BasePart is found, hence print the name only once:

for _,v in ipairs(workspace:GetChildren()) do 
		if v:IsA("BasePart") then
			print(v.Name) 
           return -- if the eval returns true, return end and stop iterating
		end
    end

Also, how on Earth did you manage to parent the workspace to a script!?
I believe you meant to instead just use the shorthand workspace, or game.Workspace.

2 Likes

Thanks this help me a loot [quote=“XxELECTROFUSIONxX, post:28, topic:626905”]
Also, how on Earth did you manage to parent the workspace to a script!?
I believe you meant to instead just use the shorthand workspace, or game.Workspace
[/quote]

Srry I copy this from a script I have and change this a bit, but again thanks a loot

2 Likes