Join the Stack Overflow Community
Stack Overflow is a community of 4.7 million programmers, just like you, helping each other.
Join them; it only takes a minute:
Sign up

What is the most efficient way to get a subarray of an array between two keys.

So for example,

$arr=array();
$arr['2014-03-01']='something';
$arr['2014-03-03']='something';
$arr['2014-02-04']='something';
$arr['2014-03-05']='something';
$arr['2014-03-07']='something';
$arr['2014-03-09']='something';
$arr['2014-01-04']='something';
$arr['2014-03-31']='something';

Get the subarray between two keys i.e. start key:2014-02-04 and end key:2014-03-07 should return an array with only:

$arr['2014-02-04']='something';
$arr['2014-03-05']='something';
$arr['2014-03-07']='something';

Is there a quick and efficient way to do this without looping through the entire array?

UPDATE: I did a benchmark here is the results:

$arr=array();
for ($i=1;$i<=1000000;$i++) {
    $arr["$i"]=$i;
}

$time_start=microtime_float();

$start = '20000';
$end   = '20010';

$offset = array_search($start, array_keys($arr));
$length = array_search($end, array_keys($arr)) - $offset + 1;
$output = array_slice($arr, $offset, $length);
print_r($output);
$time_end = microtime_float();
$time = $time_end - $time_start;
echo "TIME=$time\n";
echo "\n============\n";
$time_start=microtime_float();

$result = array();
$start = '20000';
$end   = '20010';

foreach ($arr as $key => $value) {
  if ($key >= $start && $key <= $end)
    $result[$key] = $value;
}
print_r($output);
$time_end = microtime_float();
$time = $time_end - $time_start;
echo "TIME=$time\n";

exit;

RESULTS:

Array
(
    [0] => 20000
    [1] => 20001
    [2] => 20002
    [3] => 20003
    [4] => 20004
    [5] => 20005
    [6] => 20006
    [7] => 20007
    [8] => 20008
    [9] => 20009
    [10] => 20010
)
TIME=1.8481030464172

============
Array
(
    [0] => 20000
    [1] => 20001
    [2] => 20002
    [3] => 20003
    [4] => 20004
    [5] => 20005
    [6] => 20006
    [7] => 20007
    [8] => 20008
    [9] => 20009
    [10] => 20010
)
TIME=1.700336933136

Hence, a simple loop seems to be slightly faster. The advantage increases if I make the start further down the array. You could also use break; once the latter point is reached.

share|improve this question
    
array_filter "Iterates over each value" so not prefered – Ray S. Mar 19 '14 at 8:29
    
Umm, well, unless the keys are sorted in advance, there is no way you can forego the 'iterates over each values' problem. – Achrome Mar 19 '14 at 8:30
    
keys are sorted as above. – Ray S. Mar 19 '14 at 8:31
    
You're not actually trying to get a "subarray between two keys"! You're trying to filter your data set to only include values between two boundaries, which is a different problem. Also one you'll never solve without looking at each value individually in a loop. – deceze Mar 19 '14 at 8:43
    
i will benchmark the answers and post the results. – Ray S. Mar 19 '14 at 8:44
up vote 4 down vote accepted

The most efficient way is to use a loop.

$result = array();
$start = '2014-02-04';
$end = '2014-03-07';

foreach ($arr as $key => $value) {
  // your date format is string comparable, otherwise use strtotime to convert to unix timestamp.
  if ($key >= $start && $key <= $end) {
    $result[$key] = $value;
  }
}

Or less efficient way is using array_flip to exchange the key and value, then use array_filter to the required keys, then use array_intersect_key to get the result.

share|improve this answer
    
using a huge array. anyway to do this without looping? – Ray S. Mar 19 '14 at 8:32
    
@Ray You will never be able to work with any array without looping. – deceze Mar 19 '14 at 8:33
    
@xdazz Only works as long as the keys are comparable and sorted though. Not necessarily a general solution. – deceze Mar 19 '14 at 8:33
    
@deceze The op's date format could be compared as string. And sorted? do you mean sort the result? – xdazz Mar 19 '14 at 8:37
    
no need to sort the result. – Ray S. Mar 19 '14 at 8:38

You can try with ksort, array_slice and array_search:

$start = '2014-02-04';
$end   = '2014-03-07';

ksort($arr);
$offset = array_search($start, array_keys($arr));
$length = array_search($end, array_keys($arr)) - $offset + 1;
$output = array_slice($arr, $offset, $length);

var_dump($output);

Output:

array (size=5)
  '2014-02-04' => string 'something' (length=9)
  '2014-03-01' => string 'something' (length=9)
  '2014-03-03' => string 'something' (length=9)
  '2014-03-05' => string 'something' (length=9)
  '2014-03-07' => string 'something' (length=9)
share|improve this answer
    
This solution assumes that the array is sorted. :) – Achrome Mar 19 '14 at 8:32
    
@Achrome It is. Look at ksort. – hsz Mar 19 '14 at 8:33
    
I am aware of ksort. I doubt that it's slower than a simple loop construct. – Achrome Mar 19 '14 at 8:35
1  
Question just out of curiosity - is that method anyhow faster than simple foreach? I mean wont ksort, array_slice, array_search loop that array "in the background" anyway a few times? – Marek Sadura Mar 19 '14 at 8:36
1  
This will be looping a whole lot. – deceze Mar 19 '14 at 8:36

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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