2

Suppose you have an array "value => timestamp". The values are increasing with the time but they can be reset at any moment.

For example :

$array = array(
1 => 6000,
2 => 7000,
3 => 8000,
7 => 9000,
8 => 10000,
9 => 11000,
55 => 1000,
56 => 2000,
57 => 3000,
59 => 4000,
60 => 5000,
);

I would like to retrieve all the missing values from this array.

This example would return :

array(4,5,6,58)

I don't want all the values between 9 and 55 because 9 is newer than the other higher values.

In real condition the script will deal with thousands of values so it need to be efficient.

Thanks for your help!


UPDATE : The initial array can be ordered by timestamps if it is easier for the algorithm.


UPDATE 2 : In my example the values are UNIX timestamps so they would look more like this : 1285242603 but for readability reason I simplified it.

4
  • That's very easy to do... did you try? If so, where did you fail? Commented Sep 23, 2010 at 11:28
  • 1
    What about 10, 11, …, 53, 54? Commented Sep 23, 2010 at 11:28
  • You need iterate over it and apply your conditions as you get to each element. Seems a strange requirement. Commented Sep 23, 2010 at 11:34
  • If you can please tell more about why you will require this type of functionality, then it will help the others guide you in the right direction. Commented Sep 23, 2010 at 11:38

3 Answers 3

4

Here’s another solution:

$prev = null;
$missing = array();
foreach ($array as $curr => $value) {
    if (!is_null($prev)) {
        if ($curr > $prev+1 && $value > $array[$prev]) {
            $missing = array_merge($missing, range($prev+1, $curr-1));
        }
    }
    $prev = $curr;
}
Sign up to request clarification or add additional context in comments.

Comments

1

You can do the following:

  • Keep comparing adjacent array keys. If they are consecutive you do nothing.
  • If they are not consecutive then you check their values, if the value has dropped from a higher value to a lower value, it means there was a reset so you do nothing.
  • If the value has not dropped then it is a case of missing key(s). All the numbers between the two keys(extremes not included) are part of the result.

Translated in code:

$array = array( 1 => 6000, 2 => 7000, 3 => 8000, 7 => 9000, 8 => 10000, 
                9 => 11000,55 => 1000, 56 => 2000, 57 => 3000, 59 => 4000, 
                60 => 5000,);

$keys = array_keys($array);
for($i=0;$i<count($array)-1;$i++) {
  if($array[$keys[$i]] < $array[$keys[$i+1]] && ($keys[$i+1]-$keys[$i] != 1) ) {
           print(implode(' ',range($keys[$i]+1,$keys[$i+1]-1)));
           print "\n";
   }   
}

Working link

1 Comment

Thanks for ideone.com , I didn't know this website!
1

This gives the desired result array(4,5,6,58):

$previous_value = NULL;
$temp_store = array();
$missing = array();
$keys = array_keys($array);

for($i = min($keys); $i <= max($keys); $i++)
{
    if(!array_key_exists($i, $array))
    {
        $temp_store[] = $i;
    }
    else
    {
        if($previous_value < $array[$i])
        {
            $missing = array_merge($missing, $temp_store);
        }
        $temp_store = array();
        $previous_value = $array[$i];
    }
}

var_dump($missing);

Or just use Gumbo's very smart solution ;-)

1 Comment

This solution seems slow if the gap between the min and the max is very large. This could happen in my case. But Thanks!!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.