This is a perfect application for sets. A set is an unordered collection of unique elements. It also has a few convenience functions which you could use there to make your code more concise.
A quick sets usage example with our Lua library:
require('sets')
-- A capital S is used to initialize a set
s1 = S{1,2,3}
s2 = S{3,4,5}
-- Can also initialize it from another table (notice the round parentheses this time, as opposed to the brackets before)
s3 = S(windower.ffxi.get_spells())
-- We can easily print out an entire set:
print(s1)
A set implements all common set operations:
- Union: Combination of all elements from two sets, duplicates will be ignored (+)
- Intersection: Collection of all elements that exist in both sets (*)
- Set difference: Filtering one set off all elements from another set (-)
- Counting: Returns the number of elements in a set (#)
-- This will print {1, 2, 3, 4, 5} (maybe in a different order, since order is not preserved)
print(s1 + s2)
-- This will print {3}, since that is the only element both sets have in common
print(s1 * s2)
-- This will print {1, 2}, since 3 is part of the second set and will be removed
print(s1 - s2)
-- This will print 3, since the first set has three elements
print(#s1)
You can adjust your code in various places using that. First we can create a set of all BLU spells. To do that we query the resources the same way you did (to filter for type "BlueMagic"), but then we call the keyset function. That function returns a set of all keys of the provided table, which in our case means the spell IDs:
spells = res.spells:type('BlueMagic'):keyset()
Now we use the code from earlier to get a set of all spell keys the player posesses. One thing we need to adjust is that we are interested in the table keys, not the table values, so, like above, we need to call the keyset function:
spells_have = T(windower.ffxi.get_spells()):keyset()
The "T" in front of it is just there so we can call keyset. Without it we would have to write table.keyset(windower.ffxi.get_spells()). Why this is is a bit more complicated, and I can explain it another time.
To get the set of all spells we are still missing we simply subtract the set we have from the set of all spells. Similarly we can obtain the set of BLU spells we do have using simple set operations:
missing = spells - spells_have
have = spells * spells_have
To print them we can iterate the respective loops. We can use the iterator interface the sets provide to make it a bit more convenient:
for spell in missing:it() do
windower.add_to_chat(121, " - You DO NOT have " .. res[spell].name)
end
for spell in have:it() do
windower.add_to_chat(7, " - You have " .. res[spell].name)
end
All in all we could replace your code with this (I also adjusted the formatting string a bit to show you how you can easily make longer strings work without concatenation):
require('sets')
res = require('resources')
windower.add_to_chat(24, "+----------------------------------------+")
windower.add_to_chat(24, " Simple BLU Spell Checklist by Jess")
windower.add_to_chat(24, "+----------------------------------------+")
spells = res.spells:type('BlueMagic'):keyset()
spells_have = T(windower.ffxi.get_spells()):keyset()
missing = spells - spells_have
have = spells * spells_have
windower.add_to_chat(2, "Blue Magic you have: %i/%i (%.1f%%)":format(#have, #spells, 100*#have/#spells))
for spell in have:it() do
windower.add_to_chat(7, " - You have " .. res[spell].name)
end
windower.add_to_chat(2, "Blue Magic you still need to learn: %i/%i (%.1f%%)":format(#missing, #spells, 100*#missing/#spells))
for spell in missing:it() do
windower.add_to_chat(121, " - You DO NOT have " .. res[spell].name)
end