• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

Function Performance Optimization

HeberPcL

[PowerOT.com.br]
Joined
Aug 21, 2007
Messages
1,292
Reaction score
51
Location
Brazil
GitHub
heberpcl
Hey,

I want to make is more performative function.
The idea is very simple, get my rank in an array and return rank name.

Configs example:

Code:
    fragsStorage = 22222
    titles = {
    --  Frags    /    Rank Name
        [5] = "Private First Class",
        [13] = "Specialist",
        [25] = "Corporal",
        [33] = "Sergeant",
        [47] = "Staff Sergeant",
        [100] = "Sergeant First Class"
    }

Function:

Code:
    function getMilitaryRank(playerId)
        local player         = Player(playerId)
        local fragsCount     = player:getStorageValue(fragsStorage)
        local rank             = { rank = "Private", frags = 0 }
        for k, v in pairs(titles) do
            if (math.max(0, fragsCount) > k - 1) then
                if(k - 1 > rank.frags) then
                    rank.rank, rank.frags = v, k - 1
                end
            end
        end
        return rank.rank
    end

Return:
Code:
        Sergeant


Any suggestion?

:rolleyes:
 
Last edited:
Solution
Hey,

I want to make is more performative function.
The idea is very simple, get my rank in an array and return rank name.

Configs example:

Code:
    fragsStorage = 22222
    titles = {
    --  Frags    /    Rank Name
        [5] = "Private First Class",
        [13] = "Specialist",
        [25] = "Corporal",
        [33] = "Sergeant",
        [47] = "Staff Sergeant",
        [100] = "Sergeant First Class"
    }

Function:

Code:
    function getMilitaryRank(playerId)
        local player         = Player(playerId)
        local fragsCount     = player:getStorageValue(fragsStorage)
        local rank             = { rank = "Private", frags = 0 }
        for k, v in pairs(titles) do
            if...
Code:
fragsStorage = 22222
titles = {
--  Frags    /    Rank Name
    [5] = "Private First Class",
    [10] = "Specialist",
    [15] = "Corporal",
    [20] = "Sergeant",
    [25] = "Staff Sergeant",
    [30] = "Sergeant First Class"
}

function getMilitaryRank(playerId)
    local player = Player(playerId)
    local fragsCount = player:getStorageValue(fragsStorage)
    local frags, rank = next(titles, player:getStorageValue(fragsStorage)-5)
    if fragsCount >= 30 then
        rank = titles[30]
    end
    return rank
end
try this?
 
Code:
fragsStorage = 22222
titles = {
--  Frags    /    Rank Name
    [5] = "Private First Class",
    [13] = "Specialist",
    [25] = "Corporal",
    [33] = "Sergeant",
    [47] = "Staff Sergeant",
    [100] = "Sergeant First Class"
}

function getMilitaryRank(playerId)
    local player = Player(playerId)
    local totalFrags = player:getStorageValue(fragsStorage)
    local max = #titles
    if totalFrags >= max then
        return titles[max]
    end
    for frags, title in pairs(titles) do
        local nexFrags, nexTitle = next(titles, frags)
        if frags <= totalFrags and nexFrags > totalFrags then
            return titles[title]
        end
    end
end
think this should work
best i could come up with since you wanted frags to be all over the place
 
Hey,

I want to make is more performative function.
The idea is very simple, get my rank in an array and return rank name.

Configs example:

Code:
    fragsStorage = 22222
    titles = {
    --  Frags    /    Rank Name
        [5] = "Private First Class",
        [13] = "Specialist",
        [25] = "Corporal",
        [33] = "Sergeant",
        [47] = "Staff Sergeant",
        [100] = "Sergeant First Class"
    }

Function:

Code:
    function getMilitaryRank(playerId)
        local player         = Player(playerId)
        local fragsCount     = player:getStorageValue(fragsStorage)
        local rank             = { rank = "Private", frags = 0 }
        for k, v in pairs(titles) do
            if (math.max(0, fragsCount) > k - 1) then
                if(k - 1 > rank.frags) then
                    rank.rank, rank.frags = v, k - 1
                end
            end
        end
        return rank.rank
    end

Return:
Code:
        Sergeant


Any suggestion?

:rolleyes:
Code:
function getRank(t, s)
    for i, v in pairs(t) do
        if i == s then
            return t[i]
        end
    end
    return "rank not found"
end

fragsStorage = 22222
titles = {
--  Frags    /    Rank Name
    [5] = "Private First Class",
    [10] = "Specialist",
    [15] = "Corporal",
    [20] = "Sergeant",
    [25] = "Staff Sergeant",
    [30] = "Sergeant First Class"
}

function getMilitaryRank(playerId)
    return getRank(titles, Player(playerId):getStorageValue(fragsStorage))
end
 
Code:
function getRank(t, s)
    for i, v in pairs(t) do
        if i == s then
            return t[i]
        end
    end
    return "rank not found"
end

fragsStorage = 22222
titles = {
--  Frags    /    Rank Name
    [5] = "Private First Class",
    [10] = "Specialist",
    [15] = "Corporal",
    [20] = "Sergeant",
    [25] = "Staff Sergeant",
    [30] = "Sergeant First Class"
}

function getMilitaryRank(playerId)
    return getRank(titles, Player(playerId):getStorageValue(fragsStorage))
end
that will only work if the player has the exact same amount of frags as in the key
 
Here is another function you can use to get the size of a table.
Code:
function sizeOf(t)
    local c = 0
    if next(t) then
        for i in pairs(t) do
            c = c + 1
        end
    end
    return c
end

local i = {1, {}, 5, "", a = {}, 56}

print(sizeOf(i))
-- prints 6
 
Last edited:
yep

you do realize this value is 0? or maybe 1, not sure which.
but you cant use # when keys are not in sequence
yeah forgot ive been rewriting it past couple minutes
cant use the way i did it either with pairs like that since pairs dont go in sequence

edit:
Code:
fragsStorage = 22222
titles = {
--  [{minFrags, maxFrags}] =  Rank Name
    [{5, 12}] = "Private First Class",
    [{13, 24}] = "Specialist",
    [{25, 32}] = "Corporal",
    [{33, 46}] = "Sergeant",
    [{47, 99}] = "Staff Sergeant",
    [{100}] = "Sergeant First Class"
}

function getMilitaryRank(playerId)
    local player = Player(playerId)
    local totalFrags = player:getStorageValue(fragsStorage)
    for frags, title in pairs(titles) do
        if totalFrags >= frags[1] and totalFrags <= frags[2] then
            return title
        end
    end
    return 'No rank'
end
you can use this and save frag&title information to a table with the player when you use onlook so you don't have to get the title every single time you use onLook

[playerid] = {frags, title}

if getplayerfrags ~= playerid.frags then
getmilitaryrank
end
 
Last edited:
what I would do is this:
On server startUp make a temporary table what looks like this:
{{fragCount = INT, titleName = STR}}
make sure the lowest fragCount needed has the the smallest key value for the temporary table.

Now make another table with ipairs() and as key put a table with lowest value (0 or prviousValue+1)
Final table should look like this:
Example = {
[{0, 5}] = "Private First Class",
[{6, 13}] = "Specialist",
[{14, 25}] = "Corporal",
[{26, 33}] = "Sergeant",
[{34, 47}] = "Staff Sergeant",
[{48, 100}] = "Sergeant First Class"
}
then replace the new table with the original one and use that :)
I recommend creating comment which shows how table structure looks like
-- {[INT, INT}] = STR}

yeah forgot ive been rewriting it past couple minutes
cant use the way i did it either with pairs like that since pairs dont go in sequence

edit:
Code:
fragsStorage = 22222
titles = {
--  [{minFrags, maxFrags}] =  Rank Name
    [{5, 12}] = "Private First Class",
    [{13, 24}] = "Specialist",
    [{25, 32}] = "Corporal",
    [{33, 46}] = "Sergeant",
    [{47, 99}] = "Staff Sergeant",
    [{100}] = "Sergeant First Class"
}

function getMilitaryRank(playerId)
    local player = Player(playerId)
    local totalFrags = player:getStorageValue(fragsStorage)
    for frags, title in pairs(titles) do
        if totalFrags >= frags[1] and totalFrags <= frags[2] then
            return title
        end
    end
    return 'No rank'
end
you can use this and save frag&title information to a table with the player when you use onlook so you don't have to get the title every single time you use onLook

[playerid] = {frags, title}

if getplayerfrags ~= playerid.frags then
getmilitaryrank
end

I see you editd your post, you gave the raw solution of my idea xD
but you got mistake there too. you cant compare nil value to number (You are missing 2nd value on last table)
 
Hey,

I want to make is more performative function.
The idea is very simple, get my rank in an array and return rank name.

Configs example:

Code:
    fragsStorage = 22222
    titles = {
    --  Frags    /    Rank Name
        [5] = "Private First Class",
        [13] = "Specialist",
        [25] = "Corporal",
        [33] = "Sergeant",
        [47] = "Staff Sergeant",
        [100] = "Sergeant First Class"
    }

Function:

Code:
    function getMilitaryRank(playerId)
        local player         = Player(playerId)
        local fragsCount     = player:getStorageValue(fragsStorage)
        local rank             = { rank = "Private", frags = 0 }
        for k, v in pairs(titles) do
            if (math.max(0, fragsCount) > k - 1) then
                if(k - 1 > rank.frags) then
                    rank.rank, rank.frags = v, k - 1
                end
            end
        end
        return rank.rank
    end

Return:
Code:
        Sergeant


Any suggestion?

:rolleyes:
Alright as you asked for PERFORMANCE here it is the best solution you can have for this:
Code:
titles = {
    {5, "Private First Class"},
    {13, "Specialist"},
    {25, "Corporal"},
    {33, "Sergeant"},
    {47, "Staff Sergeant"},
    {100, "Sergeant First Class"}
}

function binarysearch(t, v, l, r)
    l = l or 1
    r = r or #t
    m = math.floor((l + r) / 2)
    if l > r then
        return t[m] and t[m][2] or "No rank"
    end
    if t[m][1] > v then
        return binarysearch(t, v, l, m - 1)
    elseif t[m][1] < v then
        return binarysearch(t, v, m + 1, r)
    end
    return t[m] and t[m][2] or "No rank"
end

print(binarysearch(titles, 44))
 
Solution
Alright as you asked for PERFORMANCE here it is the best solution you can have for this:
Code:
titles = {
    {5, "Private First Class"},
    {13, "Specialist"},
    {25, "Corporal"},
    {33, "Sergeant"},
    {47, "Staff Sergeant"},
    {100, "Sergeant First Class"}
}

function binarysearch(t, v, l, r)
    l = l or 1
    r = r or #t
    m = math.floor((l + r) / 2)
    if l > r then
        return t[m] and t[m][2] or "No rank"
    end
    if t[m][1] > v then
        return binarysearch(t, v, l, m - 1)
    elseif t[m][1] < v then
        return binarysearch(t, v, m + 1, r)
    end
    return t[m] and t[m][2] or "No rank"
end

print(binarysearch(titles, 44))
is it really better though?
doesn't binary search literally compare every single digit in while loop to find a match?
Or it's a bit more fancier function that I understood from wiki?
 
is it really better though?
doesn't binary search literally compare every single digit in while loop to find a match?
Or it's a bit more fancier function that I understood from wiki?
Yes it is O(log n) (base-2) as looping through every entry is O(n).
 
Code:
fragsStorage = 22222
titles = {
--  Frags    /    Rank Name
    [5] = "Private First Class",
    [13] = "Specialist",
    [25] = "Corporal",
    [33] = "Sergeant",
    [47] = "Staff Sergeant",
    [100] = "Sergeant First Class"
}

function getMilitaryRank(playerId)
    local player = Player(playerId)
    local totalFrags = player:getStorageValue(fragsStorage)
    local max = #titles
    if totalFrags >= max then
        return titles[max]
    end
    for frags, title in pairs(titles) do
        local nexFrags, nexTitle = next(titles, frags)
        if frags <= totalFrags and nexFrags > totalFrags then
            return titles[title]
        end
    end
end
think this should work
best i could come up with since you wanted frags to be all over the place
Not work


Code:
function getRank(t, s)
    for i, v in pairs(t) do
        if i == s then
            return t[i]
        end
    end
    return "rank not found"
end

fragsStorage = 22222
titles = {
--  Frags    /    Rank Name
    [5] = "Private First Class",
    [10] = "Specialist",
    [15] = "Corporal",
    [20] = "Sergeant",
    [25] = "Staff Sergeant",
    [30] = "Sergeant First Class"
}

function getMilitaryRank(playerId)
    return getRank(titles, Player(playerId):getStorageValue(fragsStorage))
end
Return only "rank not found"



yeah forgot ive been rewriting it past couple minutes
cant use the way i did it either with pairs like that since pairs dont go in sequence

edit:
Code:
fragsStorage = 22222
titles = {
--  [{minFrags, maxFrags}] =  Rank Name
    [{5, 12}] = "Private First Class",
    [{13, 24}] = "Specialist",
    [{25, 32}] = "Corporal",
    [{33, 46}] = "Sergeant",
    [{47, 99}] = "Staff Sergeant",
    [{100}] = "Sergeant First Class"
}

function getMilitaryRank(playerId)
    local player = Player(playerId)
    local totalFrags = player:getStorageValue(fragsStorage)
    for frags, title in pairs(titles) do
        if totalFrags >= frags[1] and totalFrags <= frags[2] then
            return title
        end
    end
    return 'No rank'
end
you can use this and save frag&title information to a table with the player when you use onlook so you don't have to get the title every single time you use onLook

[playerid] = {frags, title}

if getplayerfrags ~= playerid.frags then
getmilitaryrank
end
Working and was very elegant.
:D


Alright as you asked for PERFORMANCE here it is the best solution you can have for this:
Code:
titles = {
    {5, "Private First Class"},
    {13, "Specialist"},
    {25, "Corporal"},
    {33, "Sergeant"},
    {47, "Staff Sergeant"},
    {100, "Sergeant First Class"}
}

function binarysearch(t, v, l, r)
    l = l or 1
    r = r or #t
    m = math.floor((l + r) / 2)
    if l > r then
        return t[m] and t[m][2] or "No rank"
    end
    if t[m][1] > v then
        return binarysearch(t, v, l, m - 1)
    elseif t[m][1] < v then
        return binarysearch(t, v, m + 1, r)
    end
    return t[m] and t[m][2] or "No rank"
end

print(binarysearch(titles, 44))
WoW!! Recursion is beautiful!
:eek:
 
Back
Top