ARRAY(1,3,4,6,8), find number before and after

suppose i have a number list 1,3,4,6,8.

repeat the list in circle, 1,3,4,6,8 - 1,3,4,6,8

just like an analog clock, clockwise, 12 after is 1, 2 after is 3…then back to 12 after is 1. Anticlockwise, 1 before is 12, 10 before is 9…etc

Case 1:–
if i pick number 4, then the number immediately before 4 is 3, number immediately after 4 is 6.

Case 2:–
if i pick number 8, then the number immediately before 8 is 6, number immediately after 8 is 1.

Case 3:–
pick number 1, then the number immediately before 1 is 8, number immediately after 1 is 3.

Now with PHP

Case 1: it’s easy


$picked_number = 6;

$sample_array = array(1, 3, 4, 6, 8);

foreach ($sample_array as $key => $current_number) {
    if ($current_number == $picked_number) {
        $number_before = $sample_array[$key - 1];
        $number_after = $sample_array[$key + 1];
    }
}

echo "List: 1,3,4,6,8 | Picked: $picked_number | Number immediately before: $number_before | Number immediately after: $number_after";

which show “List: 1,3,4,6,8 | Picked: 6 | Number immediately before: 4 | Number immediately after: 8”

How to find the number immediately before and after the picked number, like Case 2 and Case 3??

Case 2: $picked_number = 8;
Case 3: $picked_number = 1;

In summary, how do i find number immediately before and after the MIN or MAX number in the array??

ARRAY(1,2,3,5,7,8,9,10);

Min: 1 and Max: 10

Case 2 is easy too



$picked_number = 8;

$sample_array = array(1, 3, 4, 6, 8);

foreach ($sample_array as $key => $current_number) {
    if ($current_number == $picked_number) {
    	
    	if($picked_number == max($sample_array)){
    		$number_before = $sample_array[$key - 1];
                $number_after = $sample_array[0];
    	}elseif($picked_number == min($sample_array)){
    		$number_before = ????//I stuck here!!!;
                $number_after = $sample_array[$key + 1];
    	}else{
    		$number_before = $sample_array[$key - 1];
                $number_after = $sample_array[$key + 1];
    	}
        
    }
}

echo "List: 1,3,4,6,8 | Picked: $picked_number | Number immediately before: $number_before | Number immediately after: $number_after";

sorry all i think i’d figured out


$picked_number = 8;

$sample_array = array(1, 3, 4, 6, 8);

foreach ($sample_array as $key => $current_number) {
    if ($current_number == $picked_number) {

        if ($picked_number == min($sample_array)) {

            $number_before = max($sample_array);
            $number_after = $sample_array[$key + 1];

        } elseif ($picked_number == max($sample_array)) {

            $number_before = $sample_array[$key - 1];
            $number_after = min($sample_array);

        } else {
            $number_before = $sample_array[$key - 1];
            $number_after = $sample_array[$key + 1];
        }

    }
}

thank you. but if you have better approach do let me know here


$arr = array(1, 3, 4, 6, 8);
$number = 1;
$index = array_search($number, $arr, true);
$cnt = count($arr);
$before = ($index + $cnt - 1) % $cnt;
$after = ($index + $cnt + 1) % $cnt;
echo "$arr[$before] $number $arr[$after]";

Yes, that’s much better.

Here’s the OP code modified to demonstrate.


<?php
$sample_array = array(1, 3, 4, 6, 8);
$array_length = count($sample_array);
foreach ($sample_array as $key => $current_number) {
    $number_index = array_search($current_number, $sample_array);
    $number_before = $sample_array[($number_index + $array_length - 1) &#37; $array_length];
    $number_after = $sample_array[($number_index + $array_length + 1) % $array_length];
    echo "List: 1,3,4,6,8 | Picked: $current_number | Number immediately before: $number_before | Number immediately after: $number_after<br>";
}
?>

thank you very much.

even my version is a tag faster to execute, 0.001 - 0.003 sec. faster, i find yours version looks more pro and not clumsy like mine.


$picked_number = 1;

$sample_array = array(1, 3, 4, 6, 8);

$array_length = count($sample_array);
foreach ($sample_array as $key => $current_number) {
    $number_index = array_search($picked_number, $sample_array);
    $number_before = $sample_array[($number_index + $array_length - 1) % $array_length];
    $number_after = $sample_array[($number_index + $array_length + 1) % $array_length];
}

[QUOTE=leelong;4499530]even my version is a tag faster to execute, 0.001 - 0.003 sec. faster, i find yours version looks more pro and not clumsy like mine.

You’re welcome. let’s not concern ourselves with such minuscule speed differences. As I’m sure you well know, that’s getting into the realms of premature optimisation which is something that is frowned upon.

You now have good working code that is easy to maintain and understand, and that goes a very long way.

hi sorry, but i just found my real project isn’t as simple as that, my clumsy and yours pro versions gave very different results when i plugged the snippet.

mine works in first 50% part and yours works another last 50% part.

example if i arrange ARRAY(1,3,4,5,8,9,7)

both give me different result, and will trigger logic bugs in my project when plug in the snippet,

there is a restriction on how i can order the list, this is really headache here…

i will try sort thing out first. thank you…

part of the reason is that your version doesn’t really look for MAX-MIN value but MAX-MIN key, however it will be useful too.

If you need to do this in a loop, there’s no need to use array_search(). You already have the key, provided by the foreach loop.

If neither work, then you will need to do a better job describing what functionality you need. At this point I’m confused what you want.

leelong, is the intention that the script will be given an array of numbers (will they always be in numerical order) and be given a number (one that exists in the array) and state the previous and next numbers in the array?

that is ok now, i just changed the logic and it works on both versions as long as the number list is in ASC order, lowest to highest.

If I can ask, what was the difference in expected behaviour for:


sample_array = array(1, 3, 4, 5, 8, 9, 7);

Did you want 5 to go forward to 7, and 7 to go forward to 8?

I think that you have taken the better option, by using:


sort(sample_array);

from 1, 3, 4, 5, 8, 9, 7

by NOT aligning the order, ASC/DESC, i mean keep the order as 1, 3, 4, 5, 8, 9, 7

pick number 5, number immediately before is 4(clear enough), but number immediately AFTER the 5 must be 7 NOT 8

however the list ordered, 5,1,3,4,8,7,9 … 1,4,8,3,7,9,5 …etc.

number immediately before the picked 5 must always 4, and after must always 7

that is why both versions don’t work. :frowning:

because there are factors restricting me from using sort() - lowest to highest, rsort() - highest to lowest.

i must keep the original list order

So, using a temporarily sorted version of the array would resolve that issue.


$picked_number = 1; 
$sample_array = array(1, 3, 4, 6, 9, 7); 

$sorted_array = $sample_array;
sort($sorted_array);
$array_length = count($sorted_array); 
foreach ($sorted_array as $key => $current_number) { 
    $number_index = array_search($picked_number, $sorted_array); 
    $number_before = $sorted_array[($number_index + $array_length - 1) &#37; $array_length]; 
    $number_after = $sorted_array[($number_index + $array_length + 1) % $array_length]; 
}

List: 1,3,4,6,8,9,7 | Picked: 1 | Number immediately before: 9 | Number immediately after: 3
List: 1,3,4,6,8,9,7 | Picked: 3 | Number immediately before: 1 | Number immediately after: 4
List: 1,3,4,6,8,9,7 | Picked: 4 | Number immediately before: 3 | Number immediately after: 6
List: 1,3,4,6,8,9,7 | Picked: 6 | Number immediately before: 4 | Number immediately after: 7
List: 1,3,4,6,8,9,7 | Picked: 7 | Number immediately before: 6 | Number immediately after: 8
List: 1,3,4,6,8,9,7 | Picked: 8 | Number immediately before: 7 | Number immediately after: 9
List: 1,3,4,6,8,9,7 | Picked: 9 | Number immediately before: 8 | Number immediately after: 1

$sample_array remains as it was before.

yes, i’d thought about it and saw your reply.

i will look into the project and see if another logic bug will come bite me again!

thank you all!!