the real question is why are there “more than 1000 enemies” - that seems like an unrealistically large number on screen
suspect that’s the “entire population” for the “entire wave”, with some perhaps far offscreen, yet still participating in the collision test, likely with doubly nested loops over the entire population (so 1000*1000 tests - now THERE’s enough to notice a performance hit)
if instead you kept (and managed) a separate list of enemies “within the viewport” then life would be much simpler
and if you happened to have them in an indexed list than you could reduce the inner collision loop to a triangular array
in short: you could optimize the list storage/retrieval all you want, but to no real practical effect if the problem is at a “higher level” (ie, if you can’t fix what i suspect is an O(n2) problem in the collision loops, then worrying about the performance of pairs() is moot)
[EDIT] nah, it’s probably not quite that bad, as you don’t actually say you’re colliding enemy-vs-enemy. so ignore the O(n2) and triangular array bits, but if you’re still colliding something like 100 bullets vs 1000 enemies, where maybe half or more of those enemies are offscreen, then the rest still applies – the fastest way to do something is to not do it.