'PHP array slice from position + attempt to return fixed number of items

I'm looking for an efficient function to achieve the following. Let's say we have an array:

$a = [0, 1, 2, 3, 4, 5, 6, 7];

Slicing from a position should always return 5 values. 2 before the position index and 2 values after the position index - and of course, the position index itself.

If a position index is at the beginning of the array i.e. 0 (example 2), the function should return the next 4 values. Similarly, if the position index is at the end of the array (example 3), the function should return the previous 4 values.

Here's some examples of various indexes one could pass to the function and expected results:

$index = 3; // Result: 1, 2, 3, 4, 5. *example 1
$index = 0; // Result: 0, 1, 2, 3, 4. *example 2
$index = 7; // Result: 3, 4, 5, 6, 7. *example 3
$index = 6; // Result: 3, 4, 5, 6, 7. *example 4

As represented in examples: (example 1, example 4), the function should always attempt to catch tokens succeeding and preceding the position index - where it can, whilst always returning a total of 5 values.

The function must be bulletproof to smaller arrays: i.e if $a has 4 values, instead of 5, the function should just return everything.



Solution 1:[1]

Something like this?

@edit:

Sorry, I misread your original requirement. Second attempt:

function get_slice_of_5($index, $a) {
   if ($index+2 >= count($a)) {
     return array_slice($a, -5, 5)
   }
   else if($index-2 <= 0) {
          return array_slice($a, 0, 5)  
   }
   else return array_slice($a, $index-2, 5)
}

Solution 2:[2]

Create a start position by calculating where to start and use implode and array slice to return the string.

$a = [0, 1, 2, 3, 4, 5, 6, 7];


$index = 3; // Result: 1, 2, 3, 4, 5. *example 1
echo pages($a, $index) . "\n";

function pages($a, $index){

    if($index >= count($a)-2){
        $start = count($a)-5; // index is at end of array
    }elseif($index <=2){
        $start = 0; // index is at start
    }else{
        $start = $index-2; // index is somewhere in the middle
    }
    return implode(", ", array_slice($a, $start, 5));

}

https://3v4l.org/aNZsB

Solution 3:[3]

this is a "standalone" function to get spliced arrays of any size:

$a = [1,2,3,4,5,6,7,8,9];

echo "<pre>"; print_r(array_slicer($a, 2));

function array_slicer($arr, $start){

    // initializations
    $arr_len = count($arr);
    $min_arr_len = 5; // the size of the spliced array
    $previous_elements = 2; // number of elements to be selected before the $start
    $next_elements = 2; // number of elements to be selected after the $start
    $result = [];

    // if the $start index doesn't exist in the given array, return false!
    if($start<0 || $start>=$arr_len){
        return false;
    } elseif($arr_len <= $min_arr_len){ // if the size of the given array is less than the d size of the spliced array, return the whole array!
        return $arr;
    }

    // check if the $start has less than ($previous_elements) before it
    if($arr_len - ($arr_len - $start) < $previous_elements){

        $next_elements += ($next_elements - ($arr_len - ($arr_len - $start)));

    } elseif(($arr_len - 1 - $start) < $next_elements){ // check if the $start has less than ($next_elements) after it

        $previous_elements += ($previous_elements - ($arr_len - 1 - $start));

    }

    for($i = ($start-$previous_elements); $i <= ($start + $next_elements); $i++){
        if($i>-1 && $i<$arr_len){
            $result[] = $arr[$i];
        }
    }   

    return $result;
}

Solution 4:[4]

You can define the bounds of where the array_slice() will begin by leveraging min() and max(). Assuming your array will always have at least 5 element, you can use:

array_slice($a, min(count($a) - 5, max(0, $index - 2)), 5)

The chosen index will be in the center of the sliced array unless it cannot be.

Dynamic Code: (Demo)

$a = [0, 1, 2, 3, 4, 5, 6, 7];
$count = count($a);
$span = 5; // most sensible with odd numbers
$center = (int)($span / 2);

foreach ($a as $i => $v) {
    printf(
        "%d: %s\n",
        $i,
        implode(
            ',',
            array_slice(
                $a,
                min($count - $span, max(0, $i - $center)),
                $span
            )
        )
    );
}

Output:

0: 0,1,2,3,4
1: 0,1,2,3,4
2: 0,1,2,3,4
3: 1,2,3,4,5
4: 2,3,4,5,6
5: 3,4,5,6,7
6: 3,4,5,6,7
7: 3,4,5,6,7

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3
Solution 4 mickmackusa