Curious about loopy loops

So while I am not new to programming in general, and am relatively new to game dev, I do have a question on loops.
With everything I’ve learnt about game dev there has always been one part of the design that’s always had me curious.

Say you have a tiled top down 2D game. Where a player character runs around and shoots at zombies.
In order to draw the map you obviously need to loop over every tile and draw the tile to the canvas, that part makes sense to me.
But when you have to loop over all entities in a map to do their update function where they have player tracking code. This part seems to be the less efficient.

lets say there are 10 zombies and 2 players, 12 entities in total.
step 1: the level controller updates all entities in a loop iterating 12 times.
step 2: the zombies will then ask the level class for a list of entities in its range
step 3: the level class will then again iterate over all entities getting their co-ords and seeing if they are close
step 4: the zombie will use the list to iterate and see if there are players in the list
step 5: the zombie will then find the closest player in the list and target it

assuming all entities are within range of each other (the worst case scenario)
This will basically run like a thousand times every update cycle just for this one function.
I know you can maybe optimize the specific scenario by having 2 lists, one for the zombies and one for the players.
But some scenarios need the zombies to interact with other zombies to form a horde, so they need to find the 2 closest zombies and move towards those zombies.

So basically, what I am wondering is simply, is this the right approach to doing this kind of thing?
I mean if you add just 1 zombie that adds almost 20 extra iterations to it… what if you add 50 zombies? 100 zombies?
I’m sure there must be a better way of finding the closest 2 zombies for each zombie?

If I’ve worded anything wrong or you need more info, please let me know.
thanks in advance for any help :slight_smile: