This question is coded in pseudo-PHP, but I really don’t mind what language I get answers in (except for Ruby :-P), as this is purely hypothetical. In fact, PHP is quite possibly the worst language to be doing this type of logic in. Unfortunately, I have never done this before, so I can’t provide a real-world example. Therefore, hypothetical answers are completely acceptable.
Basically, I have lots of objects performing a task. For this example, let’s say each object is a class that downloads a file from the Internet. Each object will be downloading a different file, and the downloads are run in parallel. Obviously, some objects may finish downloading before others. The actual grabbing of data may run in threads, but that is not relevant to this question.
So we can define the object as such:
class DownloaderObject() { var $url = ''; var $downloading = false; function DownloaderObject($v){ // constructor $this->url = $v; start_downloading_in_the_background(url=$this->$url, callback=$this->finished); $this->downloading = true; } function finished() { save_the_data_somewhere(); $this->downloading = false; $this->destroy(); // actually destroys the object } }
Okay, so we have lots of these objects running:
$download1 = new DownloaderObject('http://somesite.com/latest_windows.iso'); $download2 = new DownloaderObject('http://somesite.com/kitchen_sink.iso'); $download3 = new DownloaderObject('http://somesite.com/heroes_part_1.rar');
And we can store them in an array:
$downloads = array($download1, $download2, $download3);
So we have an array full of the downloads:
array( 1 => $download1, 2 => $download2, 3 => $download3 )
And we can iterate through them like this:
print('Here are the downloads that are running:'); foreach ($downloads as $d) { print($d->url . '\n'); }
Okay, now suppose download 2 finishes, and the object is destroyed. Now we should have two objects in the array:
array( 1 => $download1, 3 => $download3 )
But there is a hole in the array! Key #2 is being unused. Also, if I wanted to start a new download, it is unclear where to insert the download into the array. The following could work:
$i = 0; while ($i < count($downloads) - 1) { if (!is_object($downloads[$i])) { $downloads[$i] = new DownloaderObject('http://somesite.com/doctorwho.iso'); break; } $i++; }
However, that is terribly inefficient (and while $i++ loops are nooby). So, another approach is to keep a counter.
function add_download($url) { global $downloads; static $download_counter; $download_counter++; $downloads[$download_counter] = new DownloaderObject($url); }
That would work, but we still get holes in the array:
array( 1 => DownloaderObject, 3 => DownloaderObject, 7 => DownloaderObject, 13 => DownloaderObject )
That’s ugly. However, is that acceptable? Should the array be ‘defragmented’, i.e. the keys rearranged to eliminate blank spaces?
Or is there another programmatic structure I should be aware of? I want a structure that I can add stuff to, remove stuff from, refer to keys in a variable, iterate through, etc., that is not an array. Does such a thing exist?
I have been coding for years, but this question has bugged me for very many of those years, and I am still not aware of an answer. This may be obvious to some programmers, but is extremely non-trivial to me.
Some good answers to this question, which reflect on the relative experience on the answerers. Thank you very much — they proved very educational.
I posted this question nearly three years ago. In hindsight, I can see my knowledge in that area was severely lacking. The biggest problem I had was that I was coming from a PHP perspective, which does not have the ability to arbitrarily pop elements. Something the other answers to this question helped me to discover was that a fundamentally superior model is ‘linked lists’.
For C, I wrote a blog post about linked lists which contains code samples (too numerous to post here) but would neatly fill the original question’s use case.
For PHP, a linked list implementation appears here, which I have never tried, but imagine it would also be the right way to deal with the above.
Interestingly, Python lists contain the
pop()method which, unlike PHP’sarray_pop(), can pop arbitrary elements and keep everything in order. For example: