PHP Check if a number is in sequence but with one missing - php

I can find if an array of values are in sequence using:
sort($arr);
if ($arr == range($arr[0], $arr[count($arr)-1])) {
return true;
}
So anything like 1,2,3,4,5, 6,7,8 will result in true but how can I find a number in sequence but with one number missing? So the expected output would be:
2,3,5,6 = true
2,5,6,8 = false
3,6,10,16 = false
5,7,8,9,10,11 = true

I just checked this and it matches the outputs you expect from your original question
function skippedValue($arr) {
sort($arr);
return sizeof(array_diff(range($arr[0], $arr[count($arr)-1]), $arr)) == 1;
}
var_dump(skippedValue([2,3,5,6])); // true
var_dump(skippedValue([2,5,6,8])); // false
var_dump(skippedValue([3,6,10,16])); // false
var_dump(skippedValue([5,7,8,9,10,11])); //true
result: bool(true) bool(false) bool(false) bool(true)

Algorithmically rather verbose, but works:
function checkAlmostSequential(array $seq, $maxSkips = 1) {
$skipped = 0;
for ($i = 0, $num = $seq[0]; $i < count($seq); $num++) {
if ($num == $seq[$i]) {
$i++;
} else {
$skipped++;
}
if ($skipped > $maxSkips) {
return false;
}
}
return true;
}
var_dump(checkAlmostSequential([2,3,5,6])); // true
var_dump(checkAlmostSequential([2,5,6,8])); // false
var_dump(checkAlmostSequential([3,6,10,16])); // false
var_dump(checkAlmostSequential([5,7,8,9,10,11])); // true

Small function to verify if is sequence
function verifySequence($arr){
sort($arr);
for($i = 0; $i < sizeof($arr) - 1; $i++){
$j = $i + 1;
if( (($arr[$i] + 1) !== $arr[$j]) && (($arr[$i] + 2) !== $arr[$j])){
return false;
}
}
return true;
}

Having misunderstood the question initially I hope this now does as expected - not the easiest to read perhaps.
$a=[1,2,5,6];
$b=[34,35,36,37,38];
$c=[5,7,8,9,10,15];
$d=[1,3,4,5,6,8];
$e=[3,6,10,16];
$f=[2,3,5,6];
function is_semi_sequential( $a ){
rsort( $a );
$c=[];
for( $i=count( $a )-1; $i >= 0; $i-- ){
if( isset( $a[ $i ] ) && isset( $a[ $i+1 ] ) && $a[ $i ] - $a[ $i + 1 ]!=1 ) $c[]=( $a[ $i ] - $a[ $i + 1 ] );
}
return count( $c ) <= 1 && array_sum( $c ) <= 2 ? true : false;
}
echo is_semi_sequential( $a ) ? 'sequential' : 'non-sequential';
echo '<br />';
echo is_semi_sequential( $b ) ? 'sequential' : 'non-sequential';
echo '<br />';
echo is_semi_sequential( $c ) ? 'sequential' : 'non-sequential';
echo '<br />';
echo is_semi_sequential( $d ) ? 'sequential' : 'non-sequential';
echo '<br />';
echo is_semi_sequential( $e ) ? 'sequential' : 'non-sequential';
echo '<br />';
echo is_semi_sequential( $f ) ? 'sequential' : 'non-sequential';
Outputs:
non-sequential
sequential
non-sequential
non-sequential
non-sequential
sequential

You can check using good old for loop
function missingItemChecker($arr, $max_missing = 1){
sort($arr);
$check_arr = range($arr[0], $arr[count($arr)-1]);
$missing = 0;
$len = count($check_arr);
$j = 0;
for($i = 0; $i < $len; $i++) {
if( $check_arr[$i] !== ($arr[$j] ?? false) ){
$missing++;
} else { $j++; }
}
return $missing == $max_missing;
}
Edit: The Logic here is,
Sort to get the Minimum and Maximum in the range using sort($arr).
Create an array of the actual sequence $check_arr = range().
Maintain a count of the numbers missing with $missing.
Loop through the real sequence to and check against the input array
to get the number of the missing elements.
If the number of missing elements is equal to the max allowed missing elements, the sequence has more than 1 numbers missing, else its either complete or only one element is missing.

If we count items that are one value more than the previous, the total will be two less than the amount of items for sequences with only one missing member.
<?php
// Assuming zero indexed and sequential keys in input array.
function missing_only_one_incremental_value_in_sequence(array $nums)
{
$count = count($nums);
$seq_count = 0;
for($i=1; $i<$count; $i++)
if($nums[$i]==$nums[$i-1]+1)
$seq_count++;
return $seq_count == $count-2;
}
var_dump(missing_only_one_incremental_value_in_sequence([2,3,5,6]));
var_dump(missing_only_one_incremental_value_in_sequence([2,5,6,8]));
Output:
bool(true)
bool(false)
For more sample inputs and outputs see here: https://3v4l.org/PFQ5d

Related

If I print my variable, I will get four times a 1 instead of a number 4

I need to divide the two numbers and get the remainder. But when I try to print the remainder by using a for loop, it will return the total times 1 of the number, like so: when the calculation is 19/5, the remainder is 4 but it returns 1111
This is my form:
<form method="post">
<input type="text" name="n1"><br>
<input type="text" name="n2"><br>
<input type="submit" name="btnClick" value="click">
</form>
And this is my PHP:
if (isset($_POST['btnClick'])) {
$number1 = $_POST['n1'];
$number2 = $_POST['n2'];
if (!is_numeric($number1) || !is_numeric($number2) || strpos($number1, ".") || strpos($number2, "."))
{
echo "error";
}
elseif ($number1 <= 0 && $number2 <= 0 || $number1 < 0 || $number2 <= 0) {
echo "error";
}
elseif(!$number1 <= 0 && !$number2 <= 0 || !$number1 < 0 || !$number2 <= 0){
$answer = $number1 / $number2;
$RoundedAnswer = round($answer);
if ($RoundedAnswer * $number2 > $number1) {
$Result = $RoundedAnswer - 1;
$ResultRemaind = $Result * $number2;
for ($i=$ResultRemaind; $i < $number1; $i++) {
echo count($i);
}
}
else{
$Result = $RoundedAnswer;
}
}
}
You need to create a counter for this. check below code:
$nU = 15;
$nG1 = 19;
$counter = 0;
for ($i=$nU; $i < $nG1; $i++) {
$counter++;
}
echo $counter; // showing 4 as you want. Counting for 15 , 16, 17 and 18
Or you can use php abs function to subtract two values as below:
$nU = 15;
$nG1 = 19;
echo abs($nG1 - $nU); // 4
Hope it helps you.
Why a loop, why not just....
<?php
$nU = 15;
$nG1 = 19;
echo $nG1 - $nU;
?>
echo (19 % 5)
// outputs 4
or a more general version that also ensures whole numbers are used. Also uses the absolute value, because the result of % can be negative in PHP.
$remainder = (int) $num1 % (int) $num2;
$remainder = abs($remainder); // convert this to a positive number, regardless of sign.
% is the modulo operator, which gives the remainder of a division of two integer numbers.
The reason why you display four times 1 is:
$ResultRemaind = $Result * $number2;
for ($i=$ResultRemaind; $i < $number1; $i++) {
echo count($i);
}
count() gives you the amount of elements in a variable. $i is just a number, i.e. $i contains exactly one element. Therefore count($i) always returns 1.
You use echo in your loop, so that means you print something (in this case 1) as many times as the loop runs. You could do something like $counter++ in the loop and then echo $counter AFTER the loop is done.
I would do it like this....
<?php
$_POST['btnClick'] = TRUE;
$_POST['n1'] = '19';
$_POST['n2'] = '5';
if ( isset ( $_POST['btnClick'] ) )
{
if ( ( ! empty ( $_POST['n1'] ) && ! empty ( $_POST['n2'] ) && ctype_digit ( $_POST['n1'] ) && ctype_digit ( $_POST['n2'] ) ) )
{
$total = round ( ( $_POST['n1'] / $_POST['n2'] ) );
if ( ( $total * $_POST['n2'] ) > $_POST['n1'] )
{
echo ( $_POST['n1'] - ( ( $total - 1 ) * $_POST['n2'] ) );
}
else
{
echo $total;
}
}
else
{
echo "Error, inputs must be type integer!";
}
}
else
{
echo "Error, no button click!";
}
?>
if you only want the number differences then you can follow the followings:
$a = 15;
$b = 19;
echo abs($a - $b);
output 4.
OR
$a = (any value);
$b = (any value);
if( $a > $b ){
echo abs($a - $b);
} else {
echo $b - $a;
}
OR
$a = (any value);
$b = (any value);
$counter = 0;
if( $a > $b ){
for ($i=$a; $i < $b; $i++) {
$counter++;
}
} else{
for ($i=$b; $i < $a; $i++){
$counter++;
}
}
echo $counter;
Try This OR Remove count function just echo $i variable
$nU = 15;
$nG1 = 19;
for ($i=$nU; $i < $nG1; $i++) {
echo $i;
echo "<br>";
}

how to find highest and second highest number in an array without using max function

I already have solution. But i think it will be more optimizable. So please provide me a solution for it. And remember that don't use predefined function of php. Like max() function.
i know there are so many ways to find it but i want best and better solution. Because my array contains more than 1 lakh records and it's taking lot of time. Or sometime site will be down.
My code :
<?php
$array = array('1', '15', '2','10',4);
echo "<pre>";
print_r($array);
echo "<pre>";
$max = 0;
$s_max=0;
for($i=0; $i<count($array); $i++)
{
$a = $array[$i];
$tmax = $max;
$ts_max = $s_max;
if($a > $tmax && $a > $ts_max)
{
$max = $a;
if($tmax > $ts_max) {
$s_max = $tmax;
} else {
$s_max = $ts_max;
}
} else if($tmax > $a && $tmax > $ts_max)
{
$max = $tmax;
if($a > $ts_max) {
$s_max = $a;
} else {
$s_max = $ts_max;
}
} else if($ts_max > $a && $ts_max > $tmax)
{
$max = $ts_max;
if($a > $tmax)
{
$s_max = $a;
} else {
$s_max = $tmax;
}
}
}
echo "Max=".$max;
echo "<br />";
echo "S_max=".$s_max;
echo "<br />";
?>
<?php
$array = array('200', '15','69','122','50','201');
$max_1 = $max_2 = 0;
for ($i=0; $i<count($array); $i++) {
if ($array[$i] > $max_1) {
$max_2 = $max_1;
$max_1 = $array[$i];
} else if ($array[$i] > $max_2 && $array[$i] != $max_2) {
$max_2 = $array[$i];
}
}
echo "Max=".$max_1;
echo "<br />";
echo "Smax 2=".$max_2;
See this solution.
<?php
$numbers = array_unique(array(1,15,2,10,4));
// rsort : sorts an array in reverse order (highest to lowest).
rsort($numbers);
echo 'Highest is -'.$numbers[0].', Second highest is -'.$numbers[1];
// O/P: Highest is -15, Second highest is -10
?>
I didn't check your solution, but in terms of complexity it's IMO optimal. If the array has no more structural information (like it's sorted) there's no way to skip entries. I.e. the best solution is in O(n) which your solution is.
This is a perfect and shortest code to find out the second largest value from the array. The below code will always return values in case the array contains only a value.
Example 1.
$arr = [5, 8, 1, 9, 24, 14, 36, 25, 78, 15, 37];
asort($arr);
$secondLargestVal = $arr[count($arr)-1];
//this will return 37
Example 2.
$arr = [5];
asort($arr);
$secondLargestVal = $arr[count($arr)-1];
//this will return 5
You can also use techniques in sorting like Bubble sort
function bubble_Sort($my_array )
{
do
{
$swapped = false;
for( $i = 0, $c = count( $my_array ) - 1; $i < $c; $i++ )
{
if( $my_array[$i] > $my_array[$i + 1] )
{
list( $my_array[$i + 1], $my_array[$i] ) =
array( $my_array[$i], $my_array[$i + 1] );
$swapped = true;
}
}
}
while( $swapped );
return $my_array;
}
$test_array = array(3, 0, 2, 5, -1, 4, 1);
echo "Original Array :\n";
echo implode(', ',$test_array );
echo "\nSorted Array\n:";
echo implode(', ',bubble_Sort($test_array)). PHP_EOL;
Original Array :
3, 0, 2, 5, -1, 4, 1
Sorted Array :
-1, 0, 1, 2, 3, 4, 5
Flow explanation
$array = array(80,250,30,40,90,10,50,60,50); // 250 2-times
$max = $max2 = 0;
foreach ($array as $key =>$val) {
if ($max < $val) {
$max2 = $max;
$max = $val;
} elseif ($max2 < $val && $max != $val) {
$max2 = $val;
}
}
echo "Highest Value is : " . $max . "<br/>"; //output: 250
echo "Second highest value is : " . $max2 . "<br/>"; //output: 90
The answer given by "Kanishka Panamaldeniya" is fine for highest value but will fail on second highest value i.e. if array has 2-similar highest value, then it will showing both Highest and second highest value same. I have sorted out it by adding one more level comparsion and it works fine.
$array = array(50,250,30,250,40,70,10,50); // 250 2-times
$max=$max2=0;
for ($i = 0; $i < count($array); $i++) {
if ($array[$i] > $max) {
$max2 = $max;
$max = $array[$i];
} else if (($array[$i] > $max2) && ($array[$i] != $max)) {
$max2 = $array[$i];
}
}
echo "Highest Value is : " . $max . "<br/>"; //output : 250
echo "Second highest value is : " . $max2 . "<br/>"; //output : 70
This code will return second max value from array
$array = array(80,250,30,250,40,90,10,50,60,50); // 250 2-times
$max=$max2=0;
for ($i = 0; $i < count($array); $i++) {
if($i == 0) {
$max2 = $array[$i];
}
if($array[$i] > $max) {
$max = $array[$i];
}
if($max > $array[$i] && $array[$i] > $max2) {
$max2 = $array[$i];
}
}
echo "Highest Value is : " . $max . "<br/>"; //output : 250
echo "Second highest value is : " . $max2 . "<br/>"; //output : 90
Two way find the second highest salary
1. Sort the data in Descending order
2. get array first value
3. Check the condition already comments
$array = [2,3,6,11,17,14,19];
$max = $array[0];
$count = count($array);
for($i=0; $i<$count;$i++)
{
for($j=$i+1;$j<$count;$j++)
{
if($array[$i] < $array[$j])
{
$temp = $array[$i];
$array[$i] = $array[$j];
$array[$j] = $temp;
}
}
}
First Method
//echo $array[1]; // Second highest value
$second ='';
for($k=0;$k<2;$k++)
{
if($array[$k] >$max)
{
$second = $array[$k];
}
}
echo $second; // Second method
Without using MAX function. Here.
$arr = [3,4,-5,-3,1,0,4,4,4];
rsort($arr); // SORT ARRAY IN DESCENDING ORDER
$largest = $arr[0]; // IN DESCENDING ORDER THE LARGEST ELEMENT IS ALWAYS THE FIRST ELEMENT
$secondLargest = 0;
foreach($arr as $val){
$secondLargest = $val; // KEEP UPDATING THE VARIABLE WITH THE VALUE UNTIL IT RECEIVES THE FIRST ELEMENT WHICH IS DIFFERENT FROM THE LARGEST VALUE
if($val != $arr[0]){
break; // BREAK OUT OF THE LOOP AS SOON AS THE VALUE IS DIFFERENT THAN THE LARGEST ELEMENT
}
}
echo $secondLargest;

How to find the highest combination while comparing three numbers in php

There are three numbers in set A {3,4,7} and in set B {2,4,7}.
It is not possible to get the result true because the the first numbers in a and b are not same.
But I need to get the result as true by comparing other two number and leaving the first number.
How is it possible to do it in PHP?
try this it will helps you.. it will display the 1 => for more number of combinations as same and 0 => for more of combination as different . in the below code the more number of combination as different so its returns 0.
<?php
$A = array(2,3,7,5,6);
$B = array(4,3,7,8,9);
$flagTrue = 0;
$flagFalse = 0;
for($i=0; $i < count($A); $i++)
{
if($A[$i] == $B[$i])
{
$flagTrue=$flagTrue+1;
}
else
{
$flagFalse=$flagFalse+1;
}
}
$var_is_greater_than_two = ($flagTrue >= $flagFalse) ? 1 : 0;
echo $var_is_greater_than_two;
?>
<?php
$a = array(3,4,7);
$b = array(2,4,7);
echo $a === $b ? 'TRUE' : 'FALSE';
echo PHP_EOL;
array_shift($a);
array_shift($b);
echo $a === $b ? 'TRUE' : 'FALSE';
?>
Shows:
FALSE TRUE
UPD:
If you need to extract values from strings, then:
$strA = '3,4,7';
$strB = '2,4,7';
$a = explode(',', $strA);
$b = explode(',', $strB);
array_shift($a);
array_shift($b);
echo $a === $b ? 'TRUE' : 'FALSE';
Should work.
<?
$A = array(2,3,7);
$B = array(4,3,7);
$isTrue=1;
for($i=1; $i < count($A); $i++) if($A[$i]!=$B[$i]) $isTrue=0;
echo $isTrue;
?>
EDIT:
If you want to return true if exactly two elements are the same, then the code would be:
$common=0;
for($i=0; $i < count($a); $i++) if($a[$i]==$b[$i]) $common++;
if($common==2) $isTrue=1;
function compareSets($a, $b) {
$result = TRUE;
$diffArray = array_diff($a, $b);
foreach ($diffArray as $key => $value) {
if ($key > 0) {
$result = FALSE;
break;
}
}
return $result;
}
<?php
$a = array(3,4,7);
$b = array(2,4,7);
for($i=0;$i<3;$i++)
{
if($a[$i] > $b[$i]
echo true;
}
?>
will give true if a is greater.

Regex and pattern in a preg_match - PHP to fit 123-23-345

I'm not very good into finding the right automation of a regex, to generate different expression, but when this comes to scripting in PHP, it becomes a pain in my ass. I can't proove myself able to write a pattern in preg_match that would 'fit' expressions like: 123-23-345...123-34-456....12-234-56.....It should be 3 groups of digits, where every group, individualy is left-to-right sorted, and every next group hasn't a digit bigger than the biggest digit of the previous group. This: 123-23-456 would be wrong, as 2 in 23 is smaller than 3 in 123. 123-43-45 is wrong again because 43 should be 34...
This should help me validate a field that may have only that type of content. It should be a regex validation not a function for parsing, splitting...
Well, there will be no regex-only solution, I think.
So here I coded the function you need:
function isValidDigitExpression($string) {
$flag = preg_match('/^(\d+)\-(\d+)\-(\d+)$/', $string, $matches);
if (!$flag) return false;
// Check correct sorting by splitting digit string to array
for ($i = 1; $i <= 3; $i++ ) {
$block[$i] = str_split($matches[$i]);
$compare = $block[$i];
sort($compare);
if ($compare != $block[$i]) return false;
}
// Compare Min and Max digits of neighboring digit blocks
return (max($block[1]) <= min($block[2]) and max($block[2]) <= min($block[3]));
}
$string = "123-34-356"; // Failure, because 3 < 4 comparing Block 2 and Block 3
echo isValidDigitExpression($string) ? "SUCCESS" : "FAILURE";
Instead of using only preg_ function, you'd need to use some other condition matching too.
<?php
$str = "123-34-456";
preg_match( "/^.*?(\d)\-(\d).*?(\d)\-(\d)/", $str, $matches );
$flag = true;
if( $matches[2] < $matches[1] )
$flag = false;
if( $matches[4] < $matches[3] )
$flag = false;
echo ( !$flag ) ? "ERROR" : "NO ERROR";
?>
Similarly, you can match the numbers in respective sections, iterate over all the literals and again use the flag for not-matching values.
Something like this:
<?php
$str = "132-34-456";
preg_match( "/^(\S+)\-(\S+)\-(\S+)$/", $str, $matches );
$flag = true;
for( $i = 0; $i < strlen($matches[1]) - 1; $i++ ) {
if( $matches[1][$i+1] < $matches[1][$i] ) {
$flag = false;
break;
}
}
for( $i = 0; $i < strlen($matches[2]) - 1; $i++ ) {
if( $matches[2][$i+1] < $matches[2][$i] ) {
$flag = false;
break;
}
}
for( $i = 0; $i < strlen($matches[3]) - 1; $i++ ) {
if( $matches[3][$i+1] < $matches[3][$i] ) {
$flag = false;
break;
}
}
echo ( !$flag ) ? "ERROR" : "NO ERROR";
?>
Obviously, this is not the best/most-optimized of the solution.

Why second passing php array element by reference generates wrong results?

I have this simple quicksort function (I got it from uncle "G")
function quicksort( &$list, $l , $r ) {
$i = $l;
$j = $r;
$tmp = $list[(int)( ($l+$r)/2 )];
do {
while( $list[$i] < $tmp )
$i++;
while( $tmp < $list[$j] )
$j--;
if( $i <= $j ) {
$w = $list[$i];
$list[$i] = $list[$j];
$list[$j] = $w;
//_swp($list[$i],$list[$j]);
$i++;
$j--;
}
}while( $i <= $j );
if( $l < $j )
quicksort($list, $l, $j);
if( $i < $r )
quicksort($list, $i, $r);
return $list;
}
And I have this little function to swap two variables.
function _swp(&$a,&$b){
$a=$a+$b;
$b=$a-$b;
$a=$a-$b;
}
How come I can't use _swp($a,$b) in quicksort function instead of this lines?
$w = $list[$i];
$list[$i] = $list[$j];
$list[$j] = $w;
If I comment out these 3 lines of code and enter call to _swp function I got bad results...
Please explain.
Best regards
the unexpected behavior is probably the "random" occurence of zeros in the sorted list. This happens because there is a special case while swapping:
if( $i <= $j ) {
// swapping here using references!
_swp($list[$i],$list[$j]);
$i++;
$j--;
}
The problem is found directly in the condition for swapping itself: if $i==$j then there are two references to the same variable. Thus calling _swp($list[$i],$list[$j]); will firstly add both variables $a = $a + $b. Considering $a and $b actually access the same variable content, $a and $b will then have the same value. In the next step $b = $a - $b will then be zero as $a is equal to $b. The third operation will leave the result to 0.
An easy solution for this is inserting another condition:
if( $i <= $j ) {
// ensure $i to be truly smaller than $j
if( $i < $j ) {
_swp($list[$i],$list[$j]);
}
$i++;
$j--;
}
I hope this will help you.
Cheers,
Fabian

Categories