33

I have an array with specific keys:

array(
    420 => array(...), 
    430 => array(...), 
    555 => array(...)
)

In my application I know current key (for example 555). And I want to get the previous array element. In this example it is array element with key 430. How can I do this in PHP? I tried to work with prev(), but for this function we should know current array element. I didn't find function, what set the current array element.

Mohammed H
  • 6,880
  • 16
  • 81
  • 127
Alex Pliutau
  • 21,392
  • 27
  • 113
  • 143

10 Answers10

33

One option:

To set the internal pointer to a certain position, you have to forward it (using key and next, maybe do a reset before to make sure you start from the beginning of the array):

while(key($array) !== $key) next($array);

Then you can use prev():

$prev_val = prev($array);
// and to get the key
$prev_key = key($array);

Depending on what you are going to do with the array afterwards, you might want to reset the internal pointer.

If the key does not exist in the array, you have an infinite loop, but this could be solved with:

 while(key($array) !== null && key($array) !== $key)

of course prev would not give you the right value anymore but I assume the key you are searching for will be in the array anyway.

Community
  • 1
  • 1
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • Cool non-foreach solution that actually works with the internal array pointer, +1 – BoltClock Jan 25 '11 at 11:12
  • 1
    the fact that we would usually go over the array with foreach but he had a different approach that works well and it also uses internal pointers. +1 – RobertPitt Jan 25 '11 at 11:14
  • 1
    So, you just perfectly explained, why these pointers just shouldn't be used. as for `key($array)` - imagine we have a regular enumerated array... ;) – Your Common Sense Jan 25 '11 at 11:29
  • Shouldn't `key($array)` be `current($array)` – RobertPitt Jan 25 '11 at 11:34
  • @RobertPitt: It's either way. `key` will return `null` if the internal pointer points outside of the array and `current` will return `false`. I think `key` is safer to use, because a value might be `false` but it is unlikely that a key will be `null`. – Felix Kling Jan 25 '11 at 11:36
  • true, nice method either way. – RobertPitt Jan 25 '11 at 11:41
  • @Eduard: Did you get an error? What happened? Did you reset the array before as I mentioned? – Felix Kling Jun 03 '13 at 15:52
  • No error, but when accessing the array with the previous key, it threw a notice, that there's no such index in the array. I haven't used any array-specific functions on that array, so I don't think a reset was needed, or is it? – Eduard Luca Jun 03 '13 at 16:05
  • @Eduard: Are you sure you used the previous key and not the value? – Felix Kling Jun 03 '13 at 18:36
  • @FelixKling well I used the previous key, to get the value :) – Eduard Luca Jun 04 '13 at 09:20
26

Solution with fast lookups: (if you have to do this more than once)

$keys = array_flip(array_keys($array));
$values = array_values($array);
return $values[$keys[555]-1];

array_flip(array_keys($array)); will return an array mapping keys to their position in the original array, e.g. array(420 => 0, 430 => 1, 555 => 2).

And array_values() returns an array mapping positions to values, e.g. array(0 => /* value of $array[420] */, ...).

So $values[$keys[555]-1] effectively returns the previous elements, given that the current one has key 555.

Alternative solution:

$keys = array_keys($array);
return $array[$keys[array_search(555, $keys)-1]];
Arnaud Le Blanc
  • 98,321
  • 23
  • 206
  • 194
11

I solved this issue in this way:

function getPrevKey($key, $hash = array()) {
    $keys = array_keys($hash);
    $found_index = array_search($key, $keys);
    if ($found_index === false || $found_index === 0)
        return false;
    return $keys[$found_index-1];
}

@return previous key or false if no previous key is available

Example:

$myhash = array(
    'foo' => 'foovalue',
    'goo' => 'goovalue',
    'moo' => 'moovalue',
    'zoo' => 'zoovalue'
);

echo "TEST: ". getPrevKey('zoo', $myhash); // prints moo
Luca Borrione
  • 16,324
  • 8
  • 52
  • 66
5

@Luca Borrione's solution was helpful. If you want to find both previous and next keys, you may use the following function:

function getAdjascentKey( $key, $hash = array(), $increment ) {
    $keys = array_keys( $hash );    
    $found_index = array_search( $key, $keys );
    if ( $found_index === false ) {
        return false;
    }
    $newindex = $found_index+$increment;
    // returns false if no result found
    return ($newindex > 0 && $newindex < sizeof($hash)) ? $keys[$newindex] : false;
}

Usage:

// previous key
getAdjascentKey( $key, $hash, -1 );

// next key
getAdjascentKey( $key, $hash, +1 );

Examples:

$myhash = array(
    'foo' => 'foovalue',
    'goo' => 'goovalue',
    'moo' => 'moovalue',
    'zoo' => 'zoovalue'
);

getAdjascentKey( 'goo', $myhash, +1 );
// moo

getAdjascentKey( 'zoo', $myhash, +1 );
// false

getAdjascentKey( 'foo', $myhash, -1 );
// false
cenk
  • 1,389
  • 14
  • 27
  • The comments in the 'Usage' section are misleading. It returns false if the searched key is not found, but will throw an `Undefined offset` notice and return `null` if the result is at the first key and you're looking for the previous. Same for the last key with the next value. – Kyro Dec 20 '16 at 06:02
2

You can iterate through the array in reverse and return the next iteration after finding the search value.

$found = false;
foreach(array_reverse($array, true) as $key=>$value) {
  if ($found) {
    print "$key => $value\n";
    break;
  } else if ($key == 555) {
    $found = true;
  }
}

http://ideone.com/2WqmC

moinudin
  • 134,091
  • 45
  • 190
  • 216
2

Just iterate over the array

$_index = null;
foreach($myarray as $index => $value)
{
    if($key == $my_index) // if($key == 550)
    {
        break;
    }
    $_index = $index;
}

echo $_index; //the prev key from 550;

An alternative solution is to get the keys of your array within an enumerated array like so:

$keys = array_keys($my_array);

as the keys array is index you can move the the previous key like so:

$required_key = (array_search(550,$keys,true) - 1);

this will fine the value of 550, and return its index within the keys, remove one to get the previous index

key we have our previous key to get the value from the original array

$value = $my_array[$required_key];
mmdanziger
  • 4,466
  • 2
  • 31
  • 47
RobertPitt
  • 56,863
  • 21
  • 114
  • 161
1

If your data is large then it might be a best practice to avoid looping. You could make your own custom function, like so:

$array = array('first'=>'111', 'second'=>'222', 'third'=>'333');

function previous($key, $array) {
  $keysArray = array_keys($array);
  $keyNumber = array_search($key, $keysArray);
  if ($keyNumber === 0) {
    $keyNumber = count($array);
  }
  return $array[$keysArray[$keyNumber - 1]];
}
var_dump(previous("second", $array));

Note that if you provide first key then it will return the last value, like a cyclic array. You can handle it however you like.

With a bit tweak, you can also generalize it to return next values.

As for why prev isnt working is because it isnt used for that purpose. It just sets the internal pointer of the array to one behind, exact inverse of next

I hope it helps

Abhay Maurya
  • 11,819
  • 8
  • 46
  • 64
0

Expanding further on the solution of Luca Borrione and cenk, so that you can wrap around the end of the array in either direction, you may use:

function getAdjascentKey($key, $hash = array(), $increment) {
    $keys = array_keys($hash);    
    $found_index = array_search($key, $keys);
    if ($found_index === min(array_keys($keys)) && $increment === -1) {
        $found_index = max(array_keys($keys))+1;
    }
    if ($found_index === max(array_keys($keys)) && $increment === +1) {
        $found_index = min(array_keys($keys))-1;
    }       
    return $keys[$found_index+$increment];
}
Daniel
  • 1
0

Here's a one-liner solution that accepts any type of keys and you can implement in a function or use as is:

$previousKey =
    array_keys($yourArray)[
        array_search(
            $currentKey,
            array_keys($yourArray)
        ) - 1
    ]
    ??
    null;

For example:

$yourArray = [
    30 => ['value1', 'value2', 'value3'],
    'keyA' => ['valueA', 'valueB', 'valueC'],
    8848 => ['valueX', 'valueY', 'valueZ']
];

echo
    array_keys($yourArray)[
        array_search(
                'keyA',
                array_keys($yourArray)
        ) - 1
    ]
    ??
    null;

Would echo 30

Here it is in the form of a function:

/**
 * Given an array and a key, returns the key that precedes it.
 * Works with hash arrays with any type of keys.
 * @param array $array The array to search the previous key in
 * @param mixed $pointerKey The key in the array that follows the key to be returned
 * @return mixed The key that precedes the specified $pointerKey in the $array, or null if the $pointerKey was not found or was the first key.
 */
function getPreviousKey(
    array $array,
    mixed $pointerKey
): mixed {
    return
        array_keys($array)[
            array_search(
                $pointerKey,
                array_keys($array)
            ) - 1
        ]
        ??
        null;
}

Please note:

  • This code will return null if the specified key was not found, or it was the first key on the array.
  • Since it makes use of PHP's null coalescing operator ??, this code needs PHP version >= 7.
Loren
  • 51
  • 1
  • 4
0

This is a simple solution for taking previous and next items, even if we are at the ends of the array.

<?php

$current_key; // the key of the item we want to search from

if (isset($array[$current_key+1])) 
{
  // get the next item if there is 
  $array_next = $array[$current_key+1];
} 
else 
{       
   // if not take the first (this means this is the end of the array)
  $array_next = $array[0];
}       

if (isset($array[$current_key-1])) 
{
   // get the previous item if there is
   $array_prev = $array[$current_key-1]; 
} 
else 
{   
  // if not take the last item (this means this is the beginning of the array)
  $array_prev = $array[count($array)-1];        
}
Mohammed H
  • 6,880
  • 16
  • 81
  • 127
O.D.
  • 9
  • 1