tags:

views:

89

answers:

5

I'm looking for a simple way to obtain the next numerical index of an array for a new element that would have been chosen by PHP as well.

Example 1:

$array = array();
$array[] = 'new index';

This would be 0 for this case.

Example 1a:

$array = array(100 => 'prefill 1');
unset($x[100]);
$x[] = 'new index';

This would be 101 for this case.

Example 2:

$array = array(-2 => 'prefill 1' );
$array[] = 'new index';

This would be 0 again for this case.

Example 3:

$array = array(-2 => 'prefill 1', 1 => 'prefill 2' );
$array[] = 'new index';

This would be 2 for this case.

I'd like now to know the next numerical key that PHP would have chosen as well for the new element in the array but w/o iterating over all the arrays values if possible.

I need this for a own array implementation via the SPL that should mimic PHP default behavior if a new element is added w/o specifying the offset.

Example 4:

$array = array(-2 => 'prefill 1', 'str-key-1' => 'prefill 2', 1 => 'prefill 3' , 'str-key-2' => 'prefill 4');
$array[] = 'new index';

This would be 2 for this case again.

Example 5:

$array = array(-2 => 'prefill-1', 'str-key-1' => 'prefill-2', 1 => 'prefill-3' , '5667 str-key-2' => 'prefill-4');
$array[] = 'new index';

This would be 2 for this case as well.

Update: I've added more examples to show some of the edge cases.

+6  A: 

Method 1:

Use end to advance the array to the end. The get the key of that item. Finally, add 1 to it to get the index of next item. Like this:

$array [ ] = 'I';
$array [4] = 'Like';
$array [ ] = 'Turtles';

end($array);
$last = key($array);
$nextindex = $last + 1;

echo $nextindex;

This outputs:

6

This method fails in cases where last index is not greatest or a string (as pointed out in comments). So, there is this better method 2 in those cases.


Method 2:

This method works on negative and string based indexes:
You can get array_keys and do a max of it, then +1 . Like this:

 $array = array(-2 => 'prefill 1', 'str-key-1' => 'prefill 2', 1 => 'prefill 3' , 'str-key-2' => 'prefill 4');
 echo max(array_keys($array)) + 1;

This outputs correctly:

2

shamittomar
False. The last element does not need to be the one with the highest index. Set $a[0], then $a[-3]. According to your approach the next index would be -2, but it really is 1.
Sjoerd
That's a nice approach, indeed, but it assumes only numeric keys are used. I've added another example that would give a wrong value for your solution.
hakre
@Sjoerd, yes. Now for that, I have added a **Method 2**
shamittomar
@hakre, the method 2 will take care of string based keys too.
shamittomar
*@shamittomar* - Well, max() is still a int based thing, so with my *Update 2/Example 5* your Method 2 outputs 5668 and not 2.
hakre
@hakre, The METHOD 2 displays answer as `2` correctly. See this in action: http://codepad.viper-7.com/0oH6o3
shamittomar
*@shamittomar* - Please see http://codepad.viper-7.com/q9kBFe which breaks it. I missed the numbering of my examples, the new snippet makes use Update 2/Example 5 which I meant. My fault, sorry.
hakre
No solution like this will work. PHP keeps track of the next index without respect to the current elements.
konforce
*@shamittomar* - sorry if the clarification of my question looks misleading. I really appreciate your suggestions, I just wanted to show where I think they are not what I've asked for. Another example might be the one with removing one element. I'm just for getting the next native numerical index PHP had chosen - as written from the beginning.
hakre
+1  A: 

Looks to me like PHP takes the next positive number after the maximum of the index values.

Mor
+1  A: 

A zend hash table has an element nNextFreeElement, which contains the number you are looking for. Every time an item is added, this field is updated to be the maximum of itself and the index + 1.

ZEND_API int _zend_hash_index_update_or_next_insert(HashTable *ht, ulong h, void *pData, uint nDataSize, void **pDest, int flag ZEND_FILE_LINE_DC)
{
    ...
    if ((long)h >= (long)ht->nNextFreeElement) {
            ht->nNextFreeElement = h < LONG_MAX ? h + 1 : LONG_MAX;
    }
    ...
 }
Sjoerd
Interesting. This might be something to implement as well then.
hakre
A: 

I don't think the necessary information is exposed to PHP scripts. Consider:

<?php
    $x = array(100 => 'foo');
    unset($x[100]);
    $x[] = 'bar';
    var_dump($x);
?>

array(1) {
  [101]=>
  string(3) "bar"
}

There would be no way to know that 101 is the next integer given that seemingly empty array, until after adding the item.

If you are building your own array class from scratch, then you could keep track of the next index via a private member variable.

konforce
I think that's the only way, indeed.
hakre
I selected this answer out of the many other good ones because it describes the problem very good with a short amount of code and explanation. Thanks a lot **konforce** for your feedaback as well as for the other answers, especially the one with end() + key(), because that is on the last added element. I solved my technical problem by adding a null value to the existing array, then getting the newly added $offset and then I added the value I needed to add. That's not a general solution but with all the help here it's something very well working in my case. I'll release the code soon under BSD.
hakre
A: 

If all else fails, you could simply test against a copy.

// Since PHP passes by copy, we don't even need to explicitly copy.
function get_next_key($copy) {
    $copy[] = 'blah';
    end($copy);
    return key($copy);
}

$key = get_next_key($array);
Casey Hope
By modifying `$copy`, you are causing the entire array to be copied. This incurs a 2x memory cost and will not give any better results than simply iterating over the original array, since the copy's "next index" will be reset, and not guaranteed to be the same as the original array.
konforce
*@konforce* - copying the array in the global namespace did not reset the next index for me, while doing it in a function (as proposed), it did.
hakre