1

I'm trying to do something but I can't find any solution, I'm also having some trouble putting it into works so here is a sample code, maybe it'll be enough to demonstrate what I'm aiming for:

$input = array
(
    'who' => 'me',
    'what' => 'car',
    'more' => 'car',
    'when' => 'today',
);

Now, I want to use array_splice() to remove (and return) one element from the array:

$spliced = key(array_splice($input, 2, 1)); // I'm only interested in the key...

The above will remove and return 1 element (third argument) from $input (first argument), at offset 2 (second argument), so $spliced will hold the value more.

I'll be iterating over $input with a foreach loop, I know the key to be spliced but the problem is I don't know its numerical offset and since array_splice only accepts integers I don't know what to do.

A very dull example:

$result = array();

foreach ($input as $key => $value)
{
    if ($key == 'more')
    {
        // Remove the index "more" from $input and add it to $result.
        $result[] = key(array_splice($input, 2 /* How do I know its 2? */, 1));
    }
}

I first though of using array_search() but it's pointless since it'll return the associative index....

How do I determine the numerical offset of a associative index?

3
  • 2
    If you just want to remove $input['more'] from your array, you can use unset($input['more']); to do so.
    – Gumbo
    Commented May 8, 2010 at 23:31
  • @Gumbo: I want to remove and return the element (key) removed. I know I could've used unset() but I was intrigued if this could be done with array_splice().
    – Alix Axel
    Commented May 8, 2010 at 23:45
  • all those array slice and dice and push and shift functions are usually quite costly in performance.
    – Gordon
    Commented May 8, 2010 at 23:52

3 Answers 3

4

Just grabbing and unsetting the value is a much better approach (and likely faster too), but anyway, you can just count along

$result = array();
$idx = 0; // init offset
foreach ($input as $key => $value)
{
    if ($key == 'more')
    {
        // Remove the index "more" from $input and add it to $result.
        $result[] = key(array_splice($input, $idx, 1));
    }
    $idx++; // count offset
}
print_R($result);
print_R($input);

gives

Array
(
    [0] => more
)
Array
(
    [who] => me
    [what] => car
    [when] => today
)

BUT Technically speaking an associative key has no numerical index. If the input array was

$input = array
(
    'who' => 'me',
    'what' => 'car',
    'more' => 'car',
    'when' => 'today',
    'foo', 'bar', 'baz'
);

then index 2 is "baz". But since array_slice accepts an offset, which is not the same as a numeric key, it uses the element found at that position in the array (in order the elements appear), which is why counting along works.

On a sidenote, with numeric keys in the array, you'd get funny results, because you are testing for equality instead of identity. Make it $key === 'more' instead to prevent 'more' getting typecasted. Since associative keys are unique you could also return after 'more' was found, because checking subsequent keys is pointless. But really:

if(array_key_exists('more', $input)) unset($input['more']);
4
  • I was hoping for a solution that didn't used counter variables but indeed, very weird results... An associate array might not have a numerical index, but it has a numerical offset - the order by which the elements were defined?
    – Alix Axel
    Commented May 8, 2010 at 23:33
  • 1
    @Alix more like the order they appear. Since you can sort the array, this is not necessarily the order in which they were defined.
    – Gordon
    Commented May 8, 2010 at 23:37
  • Indeed, see my answer bellow. =)
    – Alix Axel
    Commented May 8, 2010 at 23:40
  • Clearification The above isn't phrased too well. What I wanted to say is, an array key is not the same as it's offset. The offset refers to an element at that position in the array, but that element could have any key (assoc or numeric). Array keys do not denote position. Even numeric array keys can be reordered to appear in random order, so offset 2 could refer to an element with key 12. I'd add this clearification to the answer above, but then it would turn into a CW (which is the dumbest "feature" ever).
    – Gordon
    Commented May 9, 2010 at 9:34
3

I found the solution:

$offset = array_search('more', array_keys($input)); // 2

Even with "funny" arrays, such as:

$input = array
(
    'who' => 'me',
    'what' => 'car',
    'more' => 'car',
    'when' => 'today',
    'foo', 'bar', 'baz'
);

This:

echo '<pre>';
print_r(array_keys($input));
echo '</pre>';

Correctly outputs this:

Array
(
    [0] => who
    [1] => what
    [2] => more
    [3] => when
    [4] => 0
    [5] => 1
    [6] => 2
)

It's a trivial solution but somewhat obscure to get there.

I appreciate all the help from everyone. =)

6
  • if you intend to use that as $result = key(array_splice($input, array_search('more', array_keys($input)), 1)); do yourself a favor and benchmark it vs array_key_exists plus unset ;)
    – Gordon
    Commented May 9, 2010 at 0:03
  • Note that array_keys and array_search are O(n) while $array['more'] and unset($array['more']) are both just O(1).
    – Gumbo
    Commented May 9, 2010 at 7:12
  • @Gumbo: I know that using unset is way faster, how do you reach to the 1 and n in Big-O notation? I'd like to learn that!
    – Alix Axel
    Commented May 9, 2010 at 9:45
  • 1
    @Alix Axel: array_keys creates an array of all keys; so it has to iterate all n keys to create that array, thus O(n). array_search is iterating the whole array until it finds the needle; in the worst case the needle is not in the array, thus O(n). In contrast to that, array access is always constant (even in PHP where arrays are implemented using a hash table), thus O(1).
    – Gumbo
    Commented May 9, 2010 at 10:44
  • 1
    @Alix Axel: You can establish the limiting behavior by just counting the number of operations an algorithm takes for an input of the length n.
    – Gumbo
    Commented May 9, 2010 at 11:25
1
$i = 0;
foreach ($input as $key => $value)
{
    if ($key == 'more')
    {
        // Remove the index "more" from $input and add it to $result.
        $result[] = key(array_splice($input, $i , 1));

    }
    $i++;
}

Not the answer you're looking for? Browse other questions tagged or ask your own question.