Is this bad table design?

I am designing a weighted random spawner system that will pick an item from the table based on weights. My question is related to the table design. Obviously the table below is a dictionary in which I have keys with duplicate names. This is because the name is the object that it is, a car. But each car has some attributes that are important. I wont normally be indexing this table for data inside, so I don’t need to pick which car by name, I just pick one at random based on the weights.

Would this be considered bad table design? A dictionary with duplicate key names?

table = {
    car = {
        weight = 1,
        color = "red",
        value = 100
    },

    car = {
        weight = 5,
        color = "blue",
        value = 50
    },

    car = {
        weight = 10,
        color = "green",
        value = 10
    }
}
2 Likes

I would like feedback on the design of this table, which is an actual table :slight_smile:

1 Like

It depends on if you want an easy way to get a specific element of the table.

IE

print table[1]

Right now you have to do it via a numerical index. But if you add another item to the table the index might change.

So perhaps better is:

table = {
    car1 = {
        weight = 1,
        color = "red",
        value = 100
    };

    car2 = {
        weight = 5,
        color = "blue",
        value = 50
    };

    car3 = {
        weight = 10,
        color = "green",
        value = 10
    };
}

print table["car1"]

OR

print table.car1

Also it’s just generally easier to remember car2 than 2

UNLESS

If you are creating a dynamic list on the fly and just need to iterate through it then your version is fine, and doesn’t even need car as a key.

But they don’t have numerical keys.

@Planet_Dad no, that table won’t work. If you really need to leave ‘car’ in there, you can do it a couple of ways.

table = { -- rename this please, it overwrites the built in 'table' variable
    {
        type = "car",
        weight = 1,

Or, if you need to be able to retrieve them based on type, you can do this.

table = {
    cars = {
        {weight = 1, color = "red", value = 100},
        {weight = 5, color = "blue", value = 50}
2 Likes

Yeah, I thought I might be getting confused about tables and arrays.

But the other thing I said is right, no?

Though I don’t know which part of your post you’re referring to, you are mostly correct, and your code example would be a good solution if that’s how he wants to access it.
I don’t think he can even create a table the way he’s doing it though, I think all of those ‘car’ keys will overwrite each other and he’ll end up with only a single entry.

2 Likes

The only thing I can suggest that could change, is implement names of the vehicles into your table. As @jvdad2222 mentioned before, if you want to get a specific car, you are going to have to do something like this:

car1 = table[1]

I recommend naming your car tables to something like these:

 BlueCar = {
        weight = 5,
        color = "blue",
        value = 50
    },
  RedCar = {
        weight = 5,
        color = "blue",
        value = 50
    },

or

 ["Blue car"] = {
        weight = 5,
        color = "blue",
        value = 50
    },
  ["Red car"] = {
        weight = 5,
        color = "blue",
        value = 50
    },

I don’t see anything wrong with your table, what you are doing is perfectly fine(assuming it’s an example table)!
@Ethanthegrand14
Variable naming is just personal preference.

1 Like

@ JarodOfOrbiter Hold on a minute! Tables CAN have numerical indexes and act like arrays!

It’s very confusing!

A table with duplicate keys is cannot exist, keys must be unique. Since the cars are unique, and the purpose of this table is to assign non-unique weights to those unique cars, I would use the cars objects as keys and the weights as values.

local weightedCars = {
	[{
		color = "red",
		value = 100
	}] = 1;
	[{
		color = "blue",
		value = 50
	}] = 5;
	[{
		color = "green",
		value = 10
	}] = 10;
}

Now picking a random weighted car would look like this:

local function randomWeightedCar()
	local totalWeight = 0
	local seed
	
	for _, weight in pairs(weightedCars) do
		totalWeight += weight
	end
	
	seed = math.random() * totalWeight
	
	for car, weight in pairs(weightedCars) do
		if seed <= weight then
			return car
		end
		
		seed -= weight
	end
end

local function test()
	local colorsPicked = {}
	
	for i = 1, 1600 do
		local color = randomWeightedCar().color
		
		if not colorsPicked[color] then
			colorsPicked[color] = 0
		end
		
		colorsPicked[color] += 1
	end
	
	for color, count in pairs(colorsPicked) do
		print("picked a car with color", color, count, "times")
	end
end

test()

-- output
  20:59:13.136  picked a car with color red 103 times  -  Server  -  Script:49
  20:59:13.136  picked a car with color blue 492 times  -  Server  -  Script:49
  20:59:13.137  picked a car with color green 1005 times  -  Server  -  Script:49
5 Likes

That’s a very smart way to do it! I hadn’t thought to have the key be a table!

I also marked this as the solution, but I do want to mention everyone here had some great contributions.

thanks to all!

2 Likes