Equip best pets (with tables and dictionaries)

Hello!
Recently I’ve been making a game and was thinking a way to make an equip best pets system and while i was trying to do that, i realized that the system i am trying to make had topics that i had yet to learn about, and so I did (in a new game). Now I wanna know if there is any way my code could improve and be more optimized;
I wonder if there is any better way to do this with less “tables” i guess? Or if there is any other system that does the same but better

BestPet.lua (1.6 KB)

Otherwise here’s the code

local config = {
	Dog = {
		Common = {
			Money = 1.1,
		},
		Name = "Dog"
	},
	Cat = {
		Common = {
			Money = 1.3
		},
		Name = "Cat"
	},
	Dragon = {
		Common = {
			Money = 1.5
		},
		Name = "Dragon"
	},
	FlyingCat = {
		Common = {
			Money = 2
		},
		Name = "FlyingCat"
	},
	Lion = {
		Common = {
			Money = 20
		},
		Name = "Lion"
	}
}

local ownedPets = { --dictionary
	--["Dragon"] = 1.5,

	
}

for _, pet in pairs(config) do
	ownedPets[pet.Name] = pet.Common.Money
end

function Length(dictionary)
	local counter = 0
	for _, _ in pairs(ownedPets) do
		counter += 1
	end
	return counter
end

function Best(dictionary)
	local counter = 0
	for k, v in pairs(dictionary) do
		if counter < v then
			counter = v
		end
	end
	return counter
end

function Index(dictionary, best)
	for k, v in pairs(dictionary) do
		if v == best then
			return k
		end
	end
end

local bestPets = {}
local maxEquipped = 4
local ownedPetsAmount = Length(ownedPets)


if ownedPetsAmount < maxEquipped then --if player has less pets than the amount they can equip
	for counter = 1, ownedPetsAmount do
		local best = Best(ownedPets)
		local index = Index(ownedPets, best)
			
		table.insert(bestPets, index)
		ownedPets[index] = nil
	end
elseif ownedPetsAmount >= maxEquipped then
	for counter = 1, maxEquipped do
		local best = Best(ownedPets)
		local index = Index(ownedPets, best)

		table.insert(bestPets, index)
		ownedPets[index] = nil
	end
end

print(bestPets)
print(ownedPets)

--clear for next use
table.clear(ownedPets)
table.clear(bestPets)

The reason why i have an array (i think thats what it is) named config is because in my original game i have a module script that contains all the pets’ data (Though without the Name string and not every pet is Common). Edit: forgot to mention that this is supposed to be in the server side with some of the information passed by the client through a remotefunction (inventory gui equip best button)

Updating config dictionary

…And not every pet is common.

Do you think it would be better if you added a key that stores the rarity of the pet (e.g. “Common”, “Uncommon”, “Rare”, etc.) as its value rather than creating an array using the name of the rarity of the pet as its key that will hold keys that aren’t contingent on one rarity, but can be used for all pets of different rarities?
In other words, would you rather use your current method, or the following?

Dog = {
    Rarity = "Common",
    Money = 1.1 -- Isn't contingent on the rarity.
}

Here’s an example of your current method:

Dog = {
    Common = {
        Money = 1.1
    }
}

I don’t know why you’re doing it this way, which is why I am asking you which way you believe is best. However, using your current method, you wouldn’t know what the rarity of the pet is unless you added more code that could be avoided.
For example, let’s say the rarity is “Legendary” instead of “Common”. You wouldn’t know what the rarity is – because not all of the rarities are the same – unless you iterated over the pet array and checked if each key is a name of a rarity:

local rarities = {
    "Common",
    "Uncommon",
    "Rare",
    "Epic",
    "Legendary"
}

for key, _ in Dog do
    -- Check if `key` isn't a rarity.
    if not table.find(rarities, key) then continue end
    
    -- `key` is a rarity, ...
end

It would be easier and more efficient to just type Dog.Rarity.

To a greater or lesser degree, maybe this would also help with reducing the use of arrays. But I do not really know if it’ll affect productivity.

I wonder if there is any better way to do this with less “tables”…

Getting the “best pets”

I noticed that you have identical code in two for loops with the only difference being the end value, and the if and elseif statements that these loops are in seem unnecessary (unless it helps with productivity optimization). I will provide the snippet of code I am referring to.

Your current code:

if ownedPetsAmount < maxEquipped then
    for counter = 1, ownedPetsAmount do
        -- Code here.
    end
elseif ownedPetsAmount >= maxEquipped then
    for counter = 1, maxEquipped do
        -- Code here.
    end
end

You just need one for loop, and you can set its end value to maxEquipped.
The functions best() and index() iterate through the provided dictionary; iterating over an empty array won’t error. And if you add (table.insert() for tables) a nil value inside an array, that value/key will delete itself.

So, if ownedPets was empty – because its “length” was shorter than maxEquipped – and you call those functions and pass ownedPets as the dictionary argument, here is what will happen:

  1. best() will return 0
  2. index() will return nil, since there’d be no “pet” (key) with the value of 0.
  3. table.insert(bestPets, nil --[[index() returned nil]]) wouldn’t insert anything.
  4. ownedPets[index] = nil wouldn’t do anything.

With that being said, you just need one loop and no if/elseif statements:

for counter = 1, maxEquipped do
    -- Code here.
end

Also, pairs() and ipairs() is not needed. The for loops can automatically detect which type of array is being iterated over, and will make adjustments to the sorting (I suppose that’s how it works).
I learned this from someone else before.

well using table.sort
you can use a function

function sort(pet1,pet2)
	local pet1stats
	local pet2stats
	--run some functions
	return pet1stats>pet2stats
end

then you can use table.sort

table.sort({ownedpets},sort)

Kind of late, but I actually ended up changing it to your option and the entire system. And i had a weird system where it would know the pet Rarity. Also the reason of the last if statement with the 2 for loops, yes they are identical but the reason i did it is in case the owned amount of pets were less than what the play can actually equip.
But thanks for the suggestions!