PHP Check if number is smaller than array element values - php

This seems really simple but I can't figure out the cleanest way to do it...
Basically I have a sorted Array with numbers like this:
$array1 = [3, 7, 12, 63, 120, 512, 961];
What I need to do is check each element of the array against a number which can be like this:
$number = 320;
And I need to get the element which is next to the number in this example it would be 120 because 120 < $number < 512.
Well, my way approach which kinda works is pretty messy I think:
foreach ($i = 0; $i < count($array1); $i++) {
if ($array[$i] < $number) {
// echo "do nothing, elements are smaller than number
} else {
if ($flag == true) {
// echo "elements are not smaller anymore and flag is set"
$getValue = $array[$i-1]; // last element which was smaller
$flag == false;
}
}
}
Another problem is, I need to cover the cases if $number is smaller than the smallest element of the array or if its larger than the largest element of the array. For that case I create another Variable $t and check it with the length of the array in each iteration
$t = 0;
$len = count($array1);
// if element bigger than number and first iteration
if ($array[$i] > $number && $t == 0) {
}
$t += 1;
I left the foreach loop out here but as you can probably see it gets really long and its certainly not clean. How can it be done better?

As it is an sorted array you are working with then i recommend you to implement binary search algorithm which has O(log(n)) in time complexity .
int binary_search(int A[], int key, int imin, int imax)
{
// continue searching while [imin,imax] is not empty
while (imin <= imax)
{
// calculate the midpoint for roughly equal partition
int imid = midpoint(imin, imax);
if(A[imid] == key)
// key found at index imid
return imid;
// determine which subarray to search
else if (A[imid] < key)
// change min index to search upper subarray
imin = imid + 1;
else
// change max index to search lower subarray
imax = imid - 1;
}
// key was not found
return KEY_NOT_FOUND;
}
source: wikipedia.org

$array = [3, 7, 12, 63, 120, 512, 961];
$min = 0;
$max = count($array)-1;
$no = 320;
while ($min < $max)
{
$mid = (int)(($min+$max)/2);
if ($array[$mid] == $no) {
print $array[$mid-1]."<".$no."<".$array[$mid+1];
return;
}
else if($array[$mid] < $no) {
$min = $mid+1;
} else {
$max = $mid-1;
}
if($min == $max ) {
if($array[$min] > $no) {
print $array[$min-1]."<".$no."<".$array[$min];
return;
} else {
print $array[$min]."<".$no."<".$array[$min+1];
return;
}
}
}

Related

I dont know what to do with this PHP Code

The code below basically helps in finding out if a number is a Palindromic Number or not. Although I get my execution done with the output, I just can seem to handle all the "screams" and fatal errors that I get. How do I handle this. Just a beginner and trust you can explain in a way that I may be able to understand..
<?php
for ($num = 1; $num <= 20; ++$num){
$_array1 = str_split($num);
//print_r($_array1);
//echo "<br/>";
$_array2 = array_reverse($_array1);
//print_r($_array2);
//echo "<br/>";
$i = 0;
$j = 0;
while ($i < sizeof($_array1) && $j < sizeof($_array2)){
if ($_array1[$i] == $_array2[$j]){
++$i;
++$j;
}
}
if ($_array1[$i] == $_array2[$j]){
echo "The number $num is a Palindrome Number";
}
}
?>
You get to the size of elements, which is 1. However, if your array has only one element, which is the case for 1-digit numbers, then sizeof($_array) === 1. Which means that the biggest possible index you can use is 0. You need to change your code to something like this:
<?php
for ($num = 1; $num <= 20; ++$num){
$_array1 = str_split($num);
//print_r($_array1);
//echo "<br/>";
$_array2 = array_reverse($_array1);
//print_r($_array2);
//echo "<br/>";
$i = 0;
$j = 0;
$different = false;
while ((!$different) && ($i < sizeof($_array1))){
if ($_array1[$i] == $_array2[$j]){
++$i;
++$j;
} else {
$different = true;
}
}
if (!$different){
echo "The number $num is a Palindrome Number";
}
}
?>
But you are inversing the array without a need to do so and you are looping for unnecessarily long. I propose this function to determine whether an array is a palindrome:
function isPalindrome($input) {
$size = count($input);
for ($index = 0; $index < $size / 2; $index++) {
if ($input[$index] != $input[$size - $index - 1]) {
return false;
}
}
return true;
}
Note, that:
the function assumes that the keys of the array are numbers
the function uses a single array
the size of the array is stored into a local variable to not calculate it repeatedly
the cycle cycles until half of the array, since going beyond that is unnecessary, due to the symmetrical nature of the != operator
the function returns false when the first difference is found, to further optimize the checking
if there were no differences, the function returns true, representing that the input is a palindrome

Solving Algorithm (Josephus permutation) in PHP

Suppose 100 people line up in a circle. Counting from person 1 to person 14, remove person from the circle. Following the count order, counting again and remove the 14th person. Repeat. Who is the last person standing?
I've tried everything to solve this and it seems to not be working with dead loops.
<?php
//init array
$array = array();
for ($i = 0; $i < 100; $i++) { $array[] = $i; }
//start from 0
$pos = 0;
while (count_not_null($array) > 1) {
//reset count
$count = 0;
while (true) {
//ignore NULL for count, that position is already removed
if ($array[$pos] !== NULL) {
$count++;
if($count == 14) { break; }
}
$pos++;
//go back to beginning, we cant go over 0-99, for 100 elements
if ($pos > 99) { $pos = 0; }
}
echo "set index {$pos} to NULL!" ."<br>";
$array[$pos] = NULL;
if (count_not_null($array) === 1) { break; }
}
echo "<pre>";
print_r($array);
echo "</pre>";
//counting not null elements
function count_not_null($array) {
$count = 0;
for ($i = 0; $i < count($array); $i++) {
if ($array[$i] !== NULL) { $count++; }
}
return $count;
}
?>
For solving this with as little code as possible and quickest you could do like this:
function josephus($n,$k){
if($n ==1)
return 1;
else
return (josephus($n-1,$k)+$k-1) % $n+1;
}
echo josephus(100,14);
Here we are using an recursive statement instead, as what you are trying to solve can be defined by this mathematical statement f(n,k) = (f(n-1,k) + k) % n
For reading more about this mathematical formula you can see it here on the wiki page.
The problem is this while loop
while ($count < 14) {
if ($array[$pos] != NULL) {
$count++;
}
$pos++;
if ($pos > 99) { $pos = 0; }
}
Because you increment $pos even if count is 14 you will end with incorrect values and loop forever. Replace it with this:
while (true) {
if ($array[$pos] != NULL) {
$count++;
if($count == 14) {break;}
}
$pos++;
if ($pos > 99) { $pos = 0; }
}
Also comparing 0 to NULL won't give you the expected results as mentioned by #Barmar, so you can either change the NULL comparison, or start counting from 1
NOTE: This would be way faster if you didn't loop through array every time :D consider using a variable to count the remaining items
Anyone who stumbles across this again, here is a slightly quicker one:
function josephus($n){
$toBin = decbin($n); // to binary
$toBack = substr($toBin,1) . "1"; // remove first bit and add to end
return bindec($toBack); // back to value
}
Based on this solution.

Find specific value array multidimensional php

I'm new on PHP and I want to find the 0 and replace with the number that is missed, inside the inner array, on a multidimensional array. If the inner array has more than two 0's, it will be ignored and goes to the next.
$list = array("First"=>array(0,1,2,3,0,5,6,7,8,9),
"Second"=>array(0,1,2,3,4,5,6,7,8,9),
"Third"=>array(0,1,2,3,4,5,0,0,8,9),
"Fourth"=>array(0,1,2,3,4,5,6,7,8,0),
"Fifth"=>array(0,1,2,3,4,5,0,7,8,9),
"Sixth"=>array(0,0,0,3,4,5,6,0,0,0),
"Seventh"=>array(0,1,2,3,0,0,6,7,8,9),
"Eighth"=>array(0,1,2,3,4,5,0,7,8,9),
"Ninth"=>array(0,1,2,3,4,0,6,7,8,9),
"Tenth"=>array(0,0,2,3,4,5,6,7,8,9));
$countZero = 0;
foreach($list as $lvl) {
foreach($lvl as $ind => $val) {
if($countZero = array_count_values($lvl[$val] === 0))
$list[$ind][$val] = 45 - array_sum($ind);
echo $count;
}
}
I want all inner arrays, that have two 0's get only one, to have all numbers in sequence i.e.
"First"=>array(0,1,2,3,4,5,6,7,8,9);
Please, help me.
I tried this code below, trying to finde the 0's.
$counts = 0;
$newArr = array();
foreach($list as $lvl) {
if(is_array($lvl)) {
for($i = 0; $i < count($lvl) - 1; $i++) {
if(($lvl[$i] == 0) < 2){
$counts++;
$newArr[$i] = 45 - array_sum($lvl);
}
}
}
}
print_r($newArr);
This is a solution using array_walk:
array_walk($list,
function(&$numbers) {
$zeroIndex = 0;
foreach($numbers as $i => $number) {
if( $number === 0 ) {
if( $zeroIndex > 0 ) {
return;
}
$zeroIndex = $i;
}
}
$numbers[$zeroIndex] = $zeroIndex;
});
You don't need to count all the zeros. You just need to check if there are less than 3 zeros.
I'm saving the index (position) of zero ($zeroIndex = $i).
I'm assuming that the first number is always a zero ($zeroIndex = 0).
The index of the second zero is greater than zero. If I find a zero when the index of the last found zero is greater than zero (if( $zeroIndex > 0 )), this means that there are more than two zeros.
In fact,here is what I've done and worked.
$list = array(array(1,2,3,0,5,6,7,8,9),
array(1,2,3,4,5,6,7,8,9),
array(1,2,3,4,5,0,0,8,9),
array(1,2,3,4,5,6,7,8,0),
array(1,2,3,4,5,0,7,8,9),
array(0,0,3,4,5,6,0,0,0),
array(1,2,3,0,0,6,7,8,9),
array(1,2,3,4,5,0,7,8,9),
array(1,2,3,4,0,6,7,8,9));
for($l = 0; $l < count($list); $l++)
{
$total = 0;
$countZ = 0;
for($i=0; $i < 9; $i++)
{
if($list[$l][$i] == 0)
{
$countZ++;
$indexZero = $i;
}
$total += $list[$l][$i];
if($countZ > 1) {
break;
}
}
$list[$l][$indexZero] = 45 - $total;
}
print_r($list);
TY all.

PHP - how to tell if ALL adjacent elements in multidimensional array exist?

This is a stupid small problem we had at work that a few of us have different solutions to, and we're wondering if there's a better way to do it. I'll boil it down to something really simple for the sake of example.
Say we have a multidimensional array with the below values in it. Each value is it's own element, and each row is an array.
0a00
000b
c000
In the above "array", $array[0][1] would be "a", $array[1][3] would be "b", and $array[2][0] would be "c". What we need to do, is increment all values adjacent to non-numeric values by 1. So, the array after we've incremented the values should look like the below array. The current solution we have is to first check all 4 "corners" of the array, increment the adjacent values, then check the top and bottom rows, then check the first and last columns, and finally, check all other elements. Whenever we hit a non-numeric element, we increment all other adjacent non-numeric elements by 1. This is kind of lame/cumbersome, and we know there has to be a better way. It's pretty much building a bombsweeper board in reverse, when you know where all of the bombs are.
1a21
222b
c111
I have in mind this simple algorithm:
function getNeighborsCount($rgData, $iX, $iY)
{
if(ord($rgData[$iX][$iY])>=ord('a') && ord($rgData[$iX][$iY])<=ord('z'))
{
return null;
}
$iResult = 0;
for($i=$iX-1; $i<=$iX+1; $i++)
{
for($j=$iY-1; $j<=$iY+1; $j++)
{
if(isset($rgData[$i][$j]) &&
ord($rgData[$i][$j])>=ord('a') &&
ord($rgData[$i][$j])<=ord('z'))
{
$iResult++;
}
}
}
return $iResult;
}
-then apply it to whole array:
$rgData = [
str_split('0a00'),
str_split('000b'),
str_split('c000')
];
for($i=0; $i<count($rgData); $i++)
{
for($j=0; $j<count($rgData[$i]); $j++)
{
if($iCount = getNeighborsCount($rgData, $i, $j))
{
$rgData[$i][$j]=$iCount;
}
}
}
-this will result with
echo(join(PHP_EOL, array_map(function($rgStr)
{
return join('', $rgStr);
}, $rgData)));
to:
1a21
222b
c111
Now, about complexity. If we have N elements, it will be O(9N) since we're iterating 9 times for each element inside function.
Funny little puzzle. Try the following:
$arr = array(
array(0, 'a', 0, 0),
array(0, 0, 0, 'b'),
array('c', 0, 0, 0),
);
$max_i = count($arr);
$max_j = count($arr[0]);
for ($i = 0; $i < $max_i; $i++) {
for ($j = 0; $j < $max_j; $j++) {
if (!is_int($arr[$i][$j])) {
for ($_i = $i - 1; $_i <= $i + 1; $_i++) {
for ($_j = $j - 1; $_j <= $j + 1; $_j++) {
if (($_i == $i && $_j == $j) || $_i < 0 || $_i >= $max_i || $_j < 0 || $_j >= $max_j) {
continue;
}
if (is_int($arr[$_i][$_j])) {
$arr[$_i][$_j]++;
}
}
}
}
}
}
Not sure if this is the most efficient way, but it should be shorter than what you have.

PHP array of elements, sort by circular "animation"?

I've already asked a similar question, but I need a different effect. The original question is here.
I have a simple array. The array length is always a square number. So 16, 25, 36 etc.
$array = array('1', '2', '3', '4' ... '25');
What I do, is arrange the array with HTML so that it looks like a block with even sides.
What I want to do, is sort the elements, so that when I pass the JSON encoded array to jQuery, it will iterate the array, fade in the current block, and so I'd get a circular animation. So I'd like to sort the array kind of like this
So my sorted array would look like
$sorted = array('1', '6', '11'', '16', '21', '22', '23' .. '13');
Is there way to do so?.. Thanks
Edit:
I'm trying to do this by creating matrix-like column/row arrays with this:
$side = 5;
$elems = $side*$side;
$array = range(1,$elems);
for($i=1; $i <= $side; $i++) {
for($x=$i; $x <= $elems; $x=$x+$side) {
$columns[$i][] = $x;
}
}
for($i=1, $y=1; $i <= $elems; $i=$i+$side, $y++) {
for($x=$i; $x < $side+$i; $x++) {
$rows[$y][] = $x;
}
}
My next step is to go down the first column, at the end if it go right on the last elements column, at the end up on the last element etc.. If anyone has a better idea that would be great :)
This will work as long as the grid is always square:
<?php
// The size of the grid - 5x5 in the example above
$gridSize = 5;
// Create a 2D array representing the grid
$elements = array_chunk(range(1, pow($gridSize, 2)), $gridSize);
// Find the half way point - this will be the end of the loop since we
// want to stop in the middle
$end = ceil($gridSize / 2);
// An array to hold the result
$result = array();
// The stopping point of the current interation
$stop = $gridSize;
// Loop from start to the middle
for ($i = 0; $i < $end; $i++) {
// start in the top left corner
$x = $y = $i;
// Traverse Y top to bottom
while ($y < $stop) {
$result[] = $elements[$y++][$x];
}
$y--;
$x++;
// Traverse X left to right
while ($x < $stop) {
$result[] = $elements[$y][$x++];
}
$x--;
$y--;
// Traverse Y bottom to top
while ($y >= $gridSize - $stop) {
$result[] = $elements[$y--][$x];
}
$y++;
$x--;
// Make sure we come in a level
$stop--;
// Traverse X right to left
while ($x >= $gridSize - $stop) {
$result[] = $elements[$y][$x--];
}
}
print_r($result);
See it working
This should work. You can pass any array to circularSort function and it will return your sorted array.
/*
Get the circular sorted array
*/
function circularSort($array)
{
//Get the length of array
$arrayLength = count($array);
//Find the square root of length of array
$arrayRows = sqrt($arrayLength);
//Divide the arrays in $arrayRows
$arrayChunks = array_chunk($array,$arrayRows);
$circularArray = array();
//Call Circular Array function .. Result will be stored in $circularArray
circularArray($arrayChunks,$circularArray);
return $circularArray;
}
/*
Loop arrayChunk in following order
1. Fetch first item from each chunks
2. Fetch all items from last chunk and remove that array from arrayChunk
3. Reverse elements in each remaining chunk
4. Reverse entire arrayChunk array
5. Repeat above 4 steps until $arrayChunks is empty
*/
function circularArray(&$arrayChunks, &$circularArray)
{
if(empty($arrayChunks))
{
return true;
}
//1. Fetch first item from each chunks
foreach($arrayChunks as &$arrayChunk)
{
$circularArray[] = array_shift($arrayChunk);
}
//Fetch Last Chunk from array
$lastChunk = array_pop($arrayChunks);
//2. Fetch all items from last chunk and remove that array from arrayChunk
foreach($lastChunk as $chunkElement)
{
$circularArray[] = $chunkElement;
}
//3. Reverse elements in each remaining chunk
foreach($arrayChunks as &$arrayChunk)
{
if (is_array($arrayChunk))
{
$arrayChunk = array_reverse($arrayChunk);
}
}
$arrayChunks = array_reverse($arrayChunks);
return circularArray(&$arrayChunks, &$circularArray);
}
e.g.
$array = range(1, 25);
$circularArray = circularSort($array);
Another approach in O(n):
<?php
function circ_sort ($inArray) {
$rowSize = pow(count($inArray), 0.5);
if((int)$rowSize != $rowSize) {
throw new InvalidArgumentException();
}
$rowSize = (int)$rowSize;
$round =-1;
for ($x =-1, $y=0, $count =0; $count < count($inArray);) {
if ($y > $x) {
if ($x +1 == $y) {
$direction = 'D'; //Down
$round ++;
$max_iter = $rowSize - (2 * $round);
} else {
$direction = 'L'; //Left
$max_iter = $y - $x -1;
}
} else if ($x > $y) {
$direction = 'R'; //Right
$max_iter = $rowSize - (2 * $round) -1;
} else if ($x == $y) {
$direction = 'U'; //Up
$max_iter = $rowSize - (2 * $round) -1;
}
switch ($direction) {
case 'D': //Down
for ($iter =0; $iter < $max_iter; $iter++) {
$x++;
$circArray[] = $inArray[$x*$rowSize + $y];
$count++;
}
break;
case 'R': //Right
for ($iter =0; $iter < $max_iter; $iter++) {
$y++;
$circArray[] = $inArray[$x*$rowSize + $y];
$count++;
}
break;
case 'U': //Up
for ($iter =0; $iter < $max_iter; $iter++) {
$x--;
$circArray[] = $inArray[$x*$rowSize + $y];
$count++;
}
break;
case 'L': //Left
for ($iter =0; $iter < $max_iter; $iter++) {
$y--;
$circArray[] = $inArray[$x*$rowSize + $y];
$count++;
}
break;
}
}
return ($circArray);
}
$array = range(1, 25);
$circ_array = circ_sort($array);
var_dump($circ_array);
?>
My solution:
The trick is: The first run is 5 then two runs of 4 elements, two of 3 elements, 2 of 2 elements and two of 1 element. (5,4,4,3,3,2,2,1,1) In each run it is incremented a state module 4. Depending on the state the runs goes in one direction or other.
Here is the code:
function circularSort(array $array) {
$n2=count($array);
$n=sqrt($n2);
if((int)$n != $n) throw new InvalidArgumentException();
$Result = Array();
$run =$n; $dir=1;
$x=0; $y=-1;
$i=0;
$st=0;
while ($run) {
while ($dir) {
for ($j=0; $j<$run; $j++) {
if ($st==0) $y++;
if ($st==1) $x++;
if ($st==2) $y--;
if ($st==3) $x--;
$p=$y * $n +$x;
array_push($Result,$array[$p]);
}
$st = ($st +1) & 3;
$dir--;
}
$dir=2;
$run--;
}
return $Result;
}
$a = range(1,25);
var_dump(circularSort($a));

Categories