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

Removing specific Table variable based on String?

Asked by 5 years ago

Hey guys,

so I've been offline for a few months now, mostly to focus on Web-development, and decided to come back and repolish my LUA a bit.

I've followed a few basic tutorials to get back into things, and now tried to make my own leaderboard based on PlayerAdded and Removing events, using Tables.

I have a script, and I know what I'm doing wrong, but I can't figure out a way to fix it, so I'l point out the problem for you.

--VARIABLES
folder = script.plrs;


--TABLE
plrTable = {};


--FUNCTIONS
function remove(plrName)
    if plrName then
        folder[plrName]:Destroy();
        table.remove(plrTable, plrTable[plrName]);      --This is obviously the problem, I'm trying to remove a string index from the table, because I don't know the index of the leaving player's name. Is there a way around this?
    end
end

function add(plrName)
    local players = game.Players:GetChildren();
    for p = 1, #players do
        if not folder:FindFirstChild(plrName) then
            local plr = Instance.new("IntValue");
            plr.Name = plrName;
            plr.Parent = folder;
            table.insert(plrTable, plrName);
        end
    end
end


--EVENTS
game.Players.PlayerAdded:Connect(function(plr)
    add(plr.Name);
end)

game.Players.PlayerRemoving:Connect(function(plr)
    remove(plr.Name);
end)


--LOOP TABLE VALUES (Just for my own debugging purposes)
while wait(1) do
    print(table.concat(plrTable, ", "));
end
0
use table.remove(), table.remove(Table, index) Xx_XSanderPlayXx 160 — 5y
0
Yeah, but that won’t remove a specific playername, I would have to know the exact index of the name. User#20989 0 — 5y
0
I know that you said the other answer "seemed" more efficient, but a hash table is actually much more efficient than table.remove in a for loop. User#25115 0 — 5y
0
When I set the value at x index to nil, it removes it from the table. You don't need to worry about it ovefilling. User#25115 0 — 5y
View all comments (3 more)
0
hash tables do not have a length lol User#24403 69 — 5y
0
Oh, that was unclear to me. Apologies! User#20989 0 — 5y
0
No problem! In this scenario, there's not going to be much of a difference with respect to efficiency of the two methods presented. However, the longer the table, the more the search function has to work, and the more inefficient table.remove becomes. User#25115 0 — 5y

2 answers

Log in to vote
2
Answered by 5 years ago

Just a side note: Lua is not an acronym and should therefore not be spelt as one. Lua, not "LUA".

table.remove(table, pos) removes and returns the element at position pos, and if there is a gap, shifts elements to the left to fill in that gap, and the length of the table is decreased. If remove is called without the second argument, by default the last index is removed.

With that in mind, you can use a generic for loop and compare the value of what you want to remove.

-- an example

local tbl = {"hello", "world", "foo", "bar", "test"} -- stuff

for i, v in ipairs(tbl) do
    if v == "foo" then
        local removedValue = table.remove(tbl, i)
        print(removedValue) --> foo
    end
end

print(table.concat(tbl, ", ")) --> hello, world, bar, test 
-- everything after 'foo' was shifted to the left to fill in the gap created by the removal of 'foo'
0
Amazing! Thanks for the proper solution. I never even knew you could fill in the gaps on a table like that, so that's even better for my playerlist! Cheers User#20989 0 — 5y
Ad
Log in to vote
3
Answered by 5 years ago
Edited 5 years ago

Hello there. Your issue is a relatively common one. There are two solutions that I will present to you. A simple solution is to loop through the existing table, find the element and retrieve its index, and finally remove it from the table with table.remove. There are two problems with this method. One: looping through the table is an O(n) operation, which means that you will, in the worst case, loop through the entire table (now with a list of players, the table might not get that long. However, it is useful to note for future reference). Not only that, but as the page I linked to above states (in reference to table.insert/table.remove when you specify the index it is to remove or add at), "The last two operations are not particularly efficient, as they must move elements up and down." I will demonstrate a simple implementation here:

local function removePlayer(playerName, playerList)
    for index, playerToCheck in pairs(playerList) do
        if playerName == playerToCheck then
            table.remove(playerList, index)
        end
    end
end

A more efficient method would be to have a table with string indices (the player's name) and access that index directly when you wish to remove from the table. An example implementation:

--VARIABLES
folder = script.plrs;


--TABLE
plrTable = {};


--FUNCTIONS
function remove(plrName)
    if plrName then
        folder[plrName]:Destroy();
        plrTable[plrName] = nil -- this will effectively remove the index from the table
    end
end

function add(plrName)
    local players = game.Players:GetChildren();
    for p = 1, #players do
        if not folder:FindFirstChild(plrName) then
            local plr = Instance.new("IntValue");
            plr.Name = plrName;
            plr.Parent = folder;
            plrTable[plrName] = true
        end
    end
end
-- event connections here
while true do -- I don't recommend while wait do, more on that in a bit
    wait(1)
    local str = "" -- I do this because table.concat does not work on dictionaries
    for playerName, _ in pairs(plrTable) do
        str..playerName..", " -- adding to the string of player names
    end
    print(str)
end

Some of the reasons I don't encourage using while wait() do can be found here. If you wish, you can read all the way down the thread for further argumentation.


Finally, I would like to address a few logic issues in your code. For some reason, you create a separate function for the player adding and removing events, but you don't use them as the argument for the :Connect() method. I realize that you can't get the player name directly from the player added/removing events, but just access that property of the player in your function. Here is an example of what I mean:

-- I also recommend the use of get service
local players = game:GetService("Players")

--VARIABLES
folder = script.plrs;


--TABLE
plrTable = {};


--FUNCTIONS
function remove(player)
    local plrName = player.Name
    if plrName then
        folder[plrName]:Destroy();
        plrTable[plrName] = nil -- this will effectively remove the index from the table
    end
end

function add(player)
    local plrName = player.Name
    local playerList = players:GetPlayers() -- get players is the better method, I left this in here to make you aware, but you don't even need playerList.
    if not folder:FindFirstChild(plrName) then
        -- I don't know why you loop through the playerList
        local plr = Instance.new("IntValue");
        plr.Name = plrName;
        plr.Parent = folder;
        plrTable[plrName] = true
    end
end

players.PlayerAdded:Connect(add) -- player argument is passed implicitly to these functions
players.PlayerRemoving:Connect(remove)

while true do -- I don't recommend while wait do, more on that in a bit
    wait(1)
    local str = "" -- I do this because table.concat does not work on dictionaries
    for playerName, _ in pairs(plrTable) do
        str..playerName..", " -- adding to the string of player names
    end
    print(str)
end

I also recommend defining your functions locally, but that is up to you. Example:

local function multiply(a, b)
    return a*b
end

I hope this helps. Have a great day scripting!

0
This was an amazing answer, and I bookmarked it for future reference. I accepted the previous answer instead of this one because I feel like it's more efficient and decreases my table length with the gap filling. Your answer was amazing and I've wrote a lot down. +1 for sure! User#20989 0 — 5y

Answer this question