Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
✓ ANSWER ACCEPTED

How do I check if there's any 2 items in a table?

I'm making a sort of crafting system for my game, and I imagine the most efficient way to carry it out would be if I had a table of selected ingredients, and a method to see if there's 2 items in any order in the selected table. Example: I want to check if there's the string "foo1" anywhere in the table, and I also want to see if there's "bar2" in the table anywhere. Feel free to ask questions to verify what I'm asking, and thanks for your help!

1 answer

✓ Accepted answer

First, solve the problem of finding an item in a table (we will say where it is in particular):

function find(tab, element)
	for index, value in pairs(tab) do
		if value == element then
			return index
		end
	end
end

find will return nil if element wasn't in tab, otherwise it will return where in tab it is, ie, tab[find(tab, element)] == element.

Thus to check if something is in a table:

if find(tab, "foo") then
	-- "foo" is in `tab`

We could just string a few together to see if they have multiple things:

if find(tab, "foo") and find(tab, "bar") then
	-- they have both "foo" and "bar"

It's also straightforward to use a loop to check if all of the things are in the table:

local required = {"foo", "bar"}
local haveAll = true -- (have all *so far*)
for _, thing in pairs(required) do
	haveAll = haveAll and find(tab, thing)
end

if haveAll then
	-- they have all the things

The limitation of this solution is that we can't require more than one a thing.

if find(tab, "foo") and find(tab, "foo") then
-- same thing as
if find(tab, "foo") then
-- since both calls will return the same thing

Thus we could make a "count" (or find multiple) function:

function findAll(tab, element)
	local where = {}
	for index, value in pairs(tab) do
		if value == element then
			table.insert(where, index)
		end
	end
end

Now findAll will return an empty list if it isn't in tab, otherwise it will return a list of elements.

Thus

if #findAll(tab, "foo") >= 1 then
	-- they have at least one foo

And we can require 2 foo and 3 bar like this:

if #findAll(tab, "foo") >= 2  and findAll(tab, "bar") >= 3 then

To put this into a loop, we can make a bunch of pairings:

local required = {    {"foo", 2}, {"bar", 3}    }
local haveAll = true
for _, thing in pairs(required) do
	-- thing[1]: ingrediant
	-- thing[2]: quantity
	haveAll = haveAll and ( #findAll(tab, thing[1]) >= thing[2] )
end

Bonus option: Say you don't want to make the tables of tables like above. E.g., you want ingredients to look like this:

local required = {"foo", "foo", "bar", "bar", "bar"}
-- Arguably this is a worse format because you could miscount the
-- number; still, it is probably more natural.

Then we can just go through all of the elements of required and count how many times they appear!

local haveAll = true -- (have all *so far*)
for _, thing in pairs(required)
	haveAll = haveAll and ( #findAll(tab, thing) >= #findAll(required, thing) )
end

if haveAll then

This is somewhat inefficient because it will re-check for, say, "bar" three times -- but the behavior will be correct, and this will still be very fast for small lists like ingredient lists.

3 comments

0

Good answer

0

Excellent answer. This is EXACTLY what I was looking for. Thank you, my good man!

0

Wow. It's even better htan before. BlueTaslem, you are a genius!

This discussion is preserved as it was. New answers, comments, and votes are closed.