1

I am wondering if the built-in array structure for the contains function has any optimizations. If it does a linear search of contains every time I run it, it's at best O(n), which turns into O(n^2) because I'll be looping through another set of points to check against, however if it somehow behind the scenes sorts the array the first time 'contains' is run, then every subsequent 'contains' would be O(log(n)).

I have an array that gradually gets larger the more in depth the user gets into the application, and I am using the 'contains' a lot, so I am expecting it to slow down the application the longer the user is using the application.

If the array doesn't have any behind the scenes optimizations, then ought I build my own? (e.g. quicksort, and do an insert(newElement:, at:) every time I add to the array?)

Specifically, I'm using

[CGPoint], 

CGPointArrayVariable.contains(newCGPoint) // run 100s - 10000s of times ideally every frame, (but realistically probably every second)

and when I add new CGPoints I'm using

CGPointArrayVariable += newCGPointSet.

So, the question: Am I ok continuing to use the built in .contains function (will it be fast enough?) or should I build my own structure optimizing for the contains, and keeping the array sorted? (maybe an insertion sort would be better to use opposed to a quicksort, if that's the direction recommended)

Sulthan
  • 128,090
  • 22
  • 218
  • 270
brw59
  • 502
  • 4
  • 19
  • 4
    If you're interested in fast `contains` checks, you should be using a `Set`. – Alexander Jun 28 '17 at 17:13
  • `CGPointArrayVariable` You should definitely not name a variable like this. **1)** Swift convention is to use lowerCamelCase for variable names. **2)** We know that it's a variable because it would be lower camel case. **3)** We know that it's an array because we can option-click it to see its type. **4)** By the same merit, we know it's an array of `CGPoint`s. Give it a name that actually tells us something about it that we don't already know. For example, if it's an array of spawn points, call it just `spawnPoints`. Makes it really nice for iteration: `for spawnPoint in spawnPoints ...` – Alexander Jun 28 '17 at 17:17
  • my variables are not actually named like that, it was to make it obvious to you guys @Alexander – brw59 Jun 28 '17 at 17:19
  • What are you using it for? – GetSwifty Jun 28 '17 at 17:20
  • @PEEJWEEJ, I've created a convex hull in the x-z plane of a bunch of x-y-z object locations, and I'm using the current location of the many, potentially individually moving objects to generate the rest of the infinite map within a certain distance of the growing convex hull – brw59 Jun 28 '17 at 17:22
  • If anybody has a better idea for how to do that, please enlighten me – brw59 Jun 28 '17 at 17:24
  • Using `Set` is the first step. However, note that this is not the only option. For spatial data (e.g. points), there are special data structures based on coordinates. There are even special databases for such algorithms. – Sulthan Jun 28 '17 at 17:25
  • So basically, you're using these points to calculated how far you out the map needs to be generated? – GetSwifty Jun 28 '17 at 17:25
  • using my convex hull, I get the 'box' around it (plus some static sight distance), and loop through each index, if it's within range of the convex hull points, then it checks to see if that particular point has already been generated – brw59 Jun 28 '17 at 17:26
  • As you can imagine, once it gets to even a couple hundred squares in one direction, then it's checking to see if several thousand points have already been created for this map – brw59 Jun 28 '17 at 17:28
  • @PEEJWEEJ, I didn't answer your question very directly, Yes, but on a continual bases, as this map grows – brw59 Jun 28 '17 at 17:31
  • Is there a reason you have to track every point and not just the furthest points in each direction? This isn't exactly in my wheelhouse, but it sounds cool. – GetSwifty Jun 28 '17 at 17:32
  • I would love to do that, but I have no idea how, other than cutting out the middle by using the 'contains' function call, hence the problem... if nobody else give a great answer, I'll accept yours and use the 'set' solution. But there ought to be a way to do it better right? – brw59 Jun 28 '17 at 17:34
  • What comes to mind would be to have you map keep track of the furthest points in every direction (easy if you're generating a grid/cubes, harder if it's more granular). Then when something moves or appears, send a message to the map with the new coordinates and let the map decide if something more needs to be generated. – GetSwifty Jun 28 '17 at 17:58
  • It's hard to know what to suggest without knowing your design. – GetSwifty Jun 28 '17 at 17:59
  • ya, the problem with that is there will be instances when EVERYTHING is going to be moving at the same time, and much of the time it may not be moving outwards, so the convex hull may actually fluctuate between shrinking and growing rapidly – brw59 Jun 28 '17 at 18:01

1 Answers1

3

Doing something like that every frame will be VERY inefficient.

I would suggest re-thinking your design to avoid tracking that amount of information for every frame.

If it's absolutely necessary, building your own Type that uses a Dictionary rather than an Array should be more efficient.

Also, if it works with your use case using a Setmight be the best option.

GetSwifty
  • 7,568
  • 1
  • 29
  • 46
  • I would have thought that a Dictionary would be slower, why do you think it'd be faster? – brw59 Jun 28 '17 at 17:12
  • 3
    @brw59 Because Dictionaries and Sets (which are really just wrapped dictionaries that map every key to itself as a value) has `O(1)` insert, contains, and delete. – Alexander Jun 28 '17 at 17:13
  • You have a good argument @Alexander. Thanks for the 'Set' insight too – brw59 Jun 28 '17 at 17:16
  • 1
    @brw59 Finding a value based on a key is much faster than parsing through an array comparing it's value. Since you didn't post any code I can't tell what you're wanting to do, but as far as a "contains", `Arrays` will be much slower. – GetSwifty Jun 28 '17 at 17:17