PHP A* Pathfinding can't work for complex maze HackerRank - php
I'm trying to A* pathfinding with Pacman problem using PHP.
<?php
$_fp = fopen("php://stdin", "r");
// Node
class Node {
var $x;
var $y;
var $fCost;
var $hCost;
var $gCost = 0;
var $parent;
function __construct($x=0,$y=0){
$this->x = $x;
$this->y = $y;
}
function getNeighbours($depth = 1) {
$neighbours = array();
$operand = array(
array ('x' => -1, 'y' => 0),
array ('x' => 0, 'y' => -1),
array ('x' => 0, 'y' => 1),
array ('x' => 1, 'y' => 0)
);
foreach ($operand as $key => $value) {
$checkX = $this->x + $value['x'];
$checkY = $this->y + $value['y'];
if( $checkX >= 0 && $checkY >= 0 )
array_push( $neighbours, $node = new Node( $checkX, $checkY ) );
}
return $neighbours;
}
function fCost(){
global $food;
return $this->gCost() + $this->hCost($food);
}
function gCost(){
global $pacman;
return abs($pacman->x - $this->x) + abs($pacman->y - $this->y);
}
function hCost($destination){
return abs($destination->x - $this->x) + abs($destination->y - $this->y);
}
}
function retracePath($start,$end) {
$current = $end;
while ( $current != $start ) {
echo $current->x . " " . $current->y."<br>";
$current = $current->parent;
}
}
$pacman = new Node();
$food = new Node();
// Input data
fscanf($_fp, "%d %d", $pacman->x, $pacman->y); // Pacman's position
fscanf($_fp, "%d %d", $food->x, $food->y); // Food's position
fscanf($_fp, "%d %d", $row_size, $col_size); // For map size row and col
// Input for map by row
for($row=0; $row<$row_size; $row++) {
$map[$row] = trim(fgets(STDIN));
}
// Astar
$arr_open = array(); // set of nodes to be evaluated
$arr_close = array(); // set of nodes already evaluated
array_push($arr_open, $pacman); // add the start node to $arr_open
$key_arr_open = 0;
while( count($arr_open) > 0 ) { // loop
$current = new Node();
$current = $arr_open[$key_arr_open];
unset($arr_open[$key_arr_open]);
array_push($arr_close, $current);
if($current->x == $food->x && $current->y == $food->y) {
retracePath($pacman,$current);
echo "sukses<br>"
break;
}
$neighbours = $current->getNeighbours();
foreach ($neighbours as $key => $data) {
if($map[$data->x][$data->y] == "%" or in_array($data, $arr_close))
{
//echo "not traversable<br>";
continue;
}
$new_cost_to_neighbour = $current->gCost() + $current->hCost($data);
if( $new_cost_to_neighbour < $data->gCost() or !in_array( $data, $arr_open ) ) {
$data->gCost = $new_cost_to_neighbour;
$data->hCost = $data->hCost($food);
$data->fCost = $new_cost_to_neighbour + $data->hCost($food);
$data->parent = $current;
if( !in_array($data, $arr_open) )
{
array_push($arr_open, $data);
}
}
}
$key_arr_open ++;
}
?>
Input format : Position x and y pacman, position x and y food, count row and column of tile, then the grid. Grid format is "P" for pacman, "." for food, "-" for traversable path and "%" for wall.
The problem is when I give input with 6x6 tile like this :
%%%%%%
%-%%-%
%-%%-%
%-%%-%
%.--P%
%%%%%%
The code is work. But, if I give input with 37x37 tile with complex maze, the node in the array of open always looped. (From HackerRank)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%-------%-%-%-----------%---%-----%-%
%-%%%%%%%-%-%%%-%-%%%-%%%-%%%%%%%-%-%
%-------%-------%-%-----%-----%-%---%
%%%%%-%%%%%-%%%-%-%-%-%%%-%%%%%-%-%%%
%---%-%-%-%---%-%-%-%---%-%---%-%---%
%-%%%-%-%-%-%%%-%%%%%-%%%-%-%%%-%%%-%
%-------%-----%---%---%-----%-%-%---%
%%%-%%%%%%%%%-%%%%%%%-%%%-%%%-%-%-%-%
%-------------%-------%-%---%-----%-%
%-%-%%%%%-%-%%%-%-%-%%%-%-%%%-%%%-%-%
%-%-%-----%-%-%-%-%-----%---%-%-%-%-%
%-%-%-%%%%%%%-%-%%%%%%%%%-%%%-%-%%%-%
%-%-%-%-----%---%-----%-----%---%---%
%%%-%%%-%-%%%%%-%%%%%-%%%-%%%-%%%%%-%
%-----%-%-%-----%-%-----%-%---%-%-%-%
%-%-%-%-%-%%%-%%%-%%%-%%%-%-%-%-%-%-%
%-%-%-%-%-----------------%-%-%-----%
%%%-%%%%%%%-%-%-%%%%%-%%%-%-%%%-%%%%%
%-------%-%-%-%-----%---%-----%-%---%
%%%%%-%-%-%%%%%%%%%-%%%%%%%%%%%-%-%%%
%---%-%-----------%-%-----%---%-%---%
%-%%%-%%%%%-%%%%%%%%%-%%%%%-%-%-%%%-%
%-%---%------%--------%-----%-------%
%-%-%-%%%%%-%%%-%-%-%-%-%%%%%%%%%%%%%
%-%-%---%-----%-%-%-%-------%---%-%-%
%-%-%%%-%%%-%-%-%-%%%%%%%%%-%%%-%-%-%
%-%---%-%---%-%-%---%-%---%-%-%-----%
%-%%%-%%%-%%%%%-%%%-%-%-%%%%%-%-%%%%%
%-------%---%-----%-%-----%---%-%---%
%%%-%-%%%%%-%%%%%-%%%-%%%-%-%%%-%-%%%
%-%-%-%-%-%-%-%-----%-%---%-%---%-%-%
%-%-%%%-%-%-%-%-%%%%%%%%%-%-%-%-%-%-%
%---%---%---%-----------------%-----%
%-%-%-%-%%%-%%%-%%%%%%%-%%%-%%%-%%%-%
%.%-%-%-------%---%-------%---%-%--P%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Your program is almost correct. The problem arises from using in_array() for looking up a node in $arr_close or $arr_open, because in_array() compares not only the position $x, $y, but also the other Node members $fCost, $hCost, $gCost ...; thus it doesn't recognize that a node is already in the closed set of nodes already evaluated if those other members differ, and gets to evaluate it repeatedly.
A quick fix is to use instead of in_array() a self-defined function that as needed only compares the $x, $y members:
function in($node, $arr)
{
foreach ($arr as &$member)
if ($member->x == $node->x && $member->y == $node->y) return TRUE;
return FALSE;
}
Related
How to determine if data is increasing or decreasing in PHP
Let's say we have the following data in an array: $data1 = [3,5,7,6,8,9,13,14,17,15,16,16,16,18,22,20,21,20]; $data2 = [23,18,17,17,16,15,16,14,15,10,11,7,4,5]; As with $data1 we can say the data is increasing while in $data2 it is decreasing. Using PHP, how do you know the data is increasing or decreasing, and is there a way on how to measure know the rate of increasing as well as decreasing i.e in terms of percentage. Edit From the comments I received I got an idea and here is what I have tried. What I want to achieve; I want to know if the trend of the data coming in is upwards or downwards. Want also to know the rate at which the data is rising or droping. For example $data1 = [1,3,5]; is not the same as $data2 = [1, 20, 55];. You can see $data1 rate of increase is not the same as $data2. function increaseOrDecrease($streams = []) : array { $streams = [3,5,7,6,8,9,13,14,17,15,16,16,16,18,22,20,21,20]; // For the increasing //$streams = [23,18,17,17,16,15,16,14,15,10,11,7,4,5]; // For the decreasing $first = 0; $diff = []; foreach ($streams as $key => $number) { if ($key != 0) { $diff[] = $number - $first; } $first = $number; } $avgdifference = array_sum($diff)/count($diff); //Get the average $side = $avgdifference > 0 ? 'UP' : 'DOWN'; $avgsum = array_sum($streams)/count($streams); $percentage = abs($avgdifference)/$avgsum * 100; if ($side == 'UP') { $data = [ 'up' => true, 'percent' => $percentage, ]; }else { $data = [ 'up' => false, 'percent' => $percentage, ]; } return $data; } I would like some help to refactor this code or the best approach to solve the issue.
There are several ways to analyze data and extract a trend. The most classical method is called least squares. It's a way of fitting a line through the data. The method computes the slope and the intercept of the line. The trend is just the slope. The formulas are given here. A PHP implementation is the following: function linearRegression($x, $y) { $x_sum = array_sum($x); $y_sum = array_sum($y); $xy_sum = 0; $x2_sum = 0; $n = count($x); for($i=0;$i<$n;$i++) { $xy_sum += $x[$i] * $y[$i]; $x2_sum += $x[$i] * $x[$i]; } $beta = ($n * $xy_sum - $x_sum * $y_sum) / ($n * $x2_sum - $x_sum * $x_sum); $alpha = $y_sum / $n - $beta * $x_sum / $n; return ['alpha' => $alpha, 'beta' => $beta]; } function getTrend($data) { $x = range(1, count($data)); // [1, 2, 3, ...] $fit = linearRegression($x, $data); return $fit['beta']; // slope of fitted line } Examples: echo getTrend([1, 2, 3]); // 1 echo getTrend([1, 0, -1]); // -1 echo getTrend([3,5,7,6,8,9,13,14,17,15,16,16,16,18,22,20,21,20]); // 1.065 echo getTrend([23,18,17,17,16,15,16,14,15,10,11,7,4,5]); // -1.213
You are asking for a type of data structure that can represent ascending as well as descending data. PHP got SplMinHeap and SplMaxHeap for this purpose. These built in classes make life easer when dealing with ascending or descending datasets. A quick example ... <?php declare(strict_types=1); namespace Marcel; use SplMinHeap; $numbers = [128, 32, 64, 8, 256]; $heap = new SplMinHeap(); foreach ($numbers as $number) { $heap->insert($number); } $heap->rewind(); while($heap->valid()) { // 8, 32, 64, 128, 256 echo $heap->current() . PHP_EOL; $heap->next(); } The SplMinHeap class keeps the minimum automatically on the top. So just use heaps instead of arrays that have no structure. Same goes for SplMaxHeap that keeps the highest value on the top. Finding the differences If you want to iterate all data and finding the differences between one to the next, you just have to iterate the heap. It 's ordered anyway. $heap->rewind(); $smallest = $heap->current(); while($heap->valid()) { // 8, 32, 64, 128, 256 $current = $heap->current(); echo $current . PHP_EOL; // 0 (8 - 8), 24 (32 - 8), 32 (64 - 32), 64 (128 - 64), 128 (256 - 128) echo "difference to the value before: " . ($current - $smallest) . PHP_EOL; $smallest = $current; $heap->next(); }
I would do simple things like this $data1 = [3,5,7,6,8,9,13,14,17,15,16,16,16,18,22,20,21,20]; $data2 = [23,18,17,17,16,15,16,14,15,10,11,7,4,5]; getTrend($data1) //Returns up getTrend($data2) // Returns down function getTrend($arr) { $up = 0; $down = 0; $prev = ""; foreach($arr as $val) { if($prev != "" && $val > $prev) { $up = $val-$prev; } else if($prev != "" && $val < $prev) { $down = $prev-$val ; } $prev = $val); } if($up > $down) { return "up"; } else if($down > $up) { return "down"; } else { return "flat"; } }
Find records between two time slots in php
i have time slots like $timeslot = ['09:00-10:00', .... '23:00-00:00', '00:00-01:00']; I have records with updated time as 23:15:00, 23:30:00, 00:15:00, 09:15:00 etc. What i'm trying to find is the sum of records between each of the $timeslot. I'm not considering what day got updated, only time i'm looking for. i tried with:- $data = ['23:15:00', '23:30:00', '00:15:00', '09:15:00']; foreach($data as $val) { $cnt = 0; foreach($timeslot as $slots) { $slot = explode("-", $slots); if( (strtotime($val) > strtotime($slot[0])) && (strtotime($val) <= strtotime($slot[1])) ) { $up_time[$slot[0] . '-' . $slot[1]] = $cnt++; } } } echo '<pre>';print_r($up_time);echo '</pre>'; The expected output is:- 09:00-10:00 = 1 23:00-00:00 = 2 00:00-01:00 = 1
Strtotime is not required since your time can be compared as strings. This code works as you expected. $data = ['23:15:00', '23:30:00', '00:15:00', '09:15:00']; $timeslot = ['09:00-10:00', '23:00-00:00', '00:00-01:00']; $up_time = array(); foreach ($data as $val) { $myTime = substr($val, 0, 5); foreach ($timeslot as $slot) { $times = explode("-", $slot); if (substr($times[1], 0, 3) == "00:") { $times[1] = "24:" . substr($times[1], 3); } if ($myTime >= $times[0] && $myTime <= $times[1]) { if (!isset($up_time[$slot])) { $up_time[$slot] = 1; } else { $up_time[$slot]++; } } } } echo '<pre>'; print_r($up_time); echo '</pre>'; The if with 'substr' is needed because for midnight you have '00' and not '24' so the computer thinks is an empty set (such as hours bigger then 23 and smaller then 0). Comparison is made between string because bigger time is also a bigger string since you use 2 digits for hours. You need to count equal slots so you need an array with an element for each slot and increment if duplicate or create an element if not found (the condition '!isset'). Update for modification request $data = ['23:15:00', '23:30:00', '00:15:00', '09:15:00']; // added unused slot 8:00-9:00 $timeslot = ['08:00-09:00','09:00-10:00', '23:00-00:00', '00:00-01:00']; $up_time = array(); // new initialization foreach ($timeslot as $slot) { $up_time[$slot] = 0; } foreach ($data as $val) { $myTime = substr($val, 0, 5); foreach ($timeslot as $slot) { $times = explode("-", $slot); if (substr($times[1], 0, 3) == "00:") { $times[1] = "24:" . substr($times[1], 3); } if ($myTime >= $times[0] && $myTime <= $times[1]) { $up_time[$slot]++; // simplified } } }
Get nearest sequence result from an array and given pattern with PHP
I am trying to get year and month from the letters using established sequence. I know that the sequence is based on the following letters: $letters = array('B','C','D','F','G','H','J','K','L','M','N','P','R','S','T','V','W','X','Y','Z'); It started with 0000BBB and when it reaches 9999 it becomes BBC, BBD etc. So I don't need the numbers in that case and only letters as I have a list of last registered sequence per year and month like this: $plates = array( array('2018','KHF','KHX','KJV','KKN','KLM','KML','KNK','KPD','KPR','KPT','----','----'), array('2017','JWN','JXF','JYB','JYT','JZP','KBM','KCH','KCV','KDK','KFB','KFV','KGN'), array('2016','JLN','JMF','JMY','JNR','JPK','JRG','JRZ','JSL','JTB','JTR','JVH','JVZ'), array('2015','JCK','JCY','JDR','JFG','JFW','JGP','JHJ','JHT','JJH','JJW','JKK','JKZ'), array('2014','HVN','HVZ','HWM','HXB','HXN','HYD','HTY','HZB','HZL','HZZ','JBL','JBY'), array('2013','HNT','HPC','HPN','HPY','HRK','HRX','HSK','HSR','HSZ','HTK','HTV','HVF'), array('2012','HJC','HJM','HKB','HKL','HKX','HLK','HLW','HMD','HML','HMT','HNC','HNK'), array('2011','HBP','HCB','HCR','HDC','HDR','HFF','HFT','HGC','HGM','HGX','HHH','HHT'), array('2010','GTC','GTS','GVM','GWC','GWV','GXP','GYD','GYM','GYX','GZJ','GZT','HBG'), array('2009','GKS','GLC','GLP','GMC','GMN','GNF','GNY','GPJ','GPW','GRM','GSC','GSR'), array('2008','FZR','GBN','GCK','GDH','GFC','GFY','GGV','GHG','GHT','GJJ','GJV','GKH'), array('2007','FKY','FLV','FNB','FNZ','FRC','FSJ','FTP','FVJ','FWC','FXB','FXY','FYY'), array('2006','DVW','DWT','DXZ','DYY','FBC','FCJ','FDP','FFK','FGF','FHD','FJD','FKC'), array('2005','DFZ','DGX','DHZ','DKB','DLD','DMJ','DNP','DPK','DRG','DSC','DTB','DVB'), array('2004','CRV','CSS','CTT','CVR','CWR','CXT','CYY','CZP','DBJ','DCH','DDG','DFF'), array('2003','CDV','CFM','CGJ','CHF','CJC','CKB','CLD','CLV','CMM','CNK','CPF','CRC'), array('2002','BSL','BTF','BTZ','BVW','BWT','BXP','BYP','BZF','BZV','CBP','CCH','CDC'), array('2001','BFJ','BGF','BHG','BJC','BKB','BLC','BMF','BMW','BNL','BPG','BRB','BRT'), array('2000','---','---','---','---','---','---','---','---','BBJ','BCD','BCY','BDR') ); That means that array index 0 is the year and from 1 to 12 would be month. I am trying to find a match but then realize I can not search exact value and need to look for nearest value based on letters. I would deeply appreciate if anyone could direct me in right direction what would be the best method of doing this. This is a test so far but this will just return an exact match, I would have to search any possible letters such as KHW as an example that would have to match as nearest value to KHX foreach ($plates as $key => $val) { $search = array_search('KHX', $plates[$key]); if($search){ echo $search."\n"; echo $plates[$key][0]; break; } }
You can solve it with O(log n) with a binary search. But in a more straightforward solution, you can solve it with O(n). You can calculate the difference between each word with the below algorithm. <?php function strToInt($str) { $result = 0; for ($i = 0; $i < strlen($str); $i++) { $result = $result * 100 + ord($str[$i]); } return $result; } function find($searchStr) { $plates = [ ['2018','KHF','KHX','KJV','KKN','KLM','KML','KNK','KPD','KPR','KPT','----','----'], ['2017','JWN','JXF','JYB','JYT','JZP','KBM','KCH','KCV','KDK','KFB','KFV','KGN'], ['2016','JLN','JMF','JMY','JNR','JPK','JRG','JRZ','JSL','JTB','JTR','JVH','JVZ'], ['2015','JCK','JCY','JDR','JFG','JFW','JGP','JHJ','JHT','JJH','JJW','JKK','JKZ'], ['2014','HVN','HVZ','HWM','HXB','HXN','HYD','HTY','HZB','HZL','HZZ','JBL','JBY'], ['2013','HNT','HPC','HPN','HPY','HRK','HRX','HSK','HSR','HSZ','HTK','HTV','HVF'], ['2012','HJC','HJM','HKB','HKL','HKX','HLK','HLW','HMD','HML','HMT','HNC','HNK'], ['2011','HBP','HCB','HCR','HDC','HDR','HFF','HFT','HGC','HGM','HGX','HHH','HHT'], ['2010','GTC','GTS','GVM','GWC','GWV','GXP','GYD','GYM','GYX','GZJ','GZT','HBG'], ['2009','GKS','GLC','GLP','GMC','GMN','GNF','GNY','GPJ','GPW','GRM','GSC','GSR'], ['2008','FZR','GBN','GCK','GDH','GFC','GFY','GGV','GHG','GHT','GJJ','GJV','GKH'], ['2007','FKY','FLV','FNB','FNZ','FRC','FSJ','FTP','FVJ','FWC','FXB','FXY','FYY'], ['2006','DVW','DWT','DXZ','DYY','FBC','FCJ','FDP','FFK','FGF','FHD','FJD','FKC'], ['2005','DFZ','DGX','DHZ','DKB','DLD','DMJ','DNP','DPK','DRG','DSC','DTB','DVB'], ['2004','CRV','CSS','CTT','CVR','CWR','CXT','CYY','CZP','DBJ','DCH','DDG','DFF'], ['2003','CDV','CFM','CGJ','CHF','CJC','CKB','CLD','CLV','CMM','CNK','CPF','CRC'], ['2002','BSL','BTF','BTZ','BVW','BWT','BXP','BYP','BZF','BZV','CBP','CCH','CDC'], ['2001','BFJ','BGF','BHG','BJC','BKB','BLC','BMF','BMW','BNL','BPG','BRB','BRT'], ['2000','---','---','---','---','---','---','---','---','BBJ','BCD','BCY','BDR'] ]; $minYear = null; $minKey = null; $minDiff = strToInt('ZZZ'); $searchInt = strToInt($searchStr); for ($i = 0; $i < count($plates); $i++) { for ($j = 1; $j < 13; $j++) { if(abs($searchInt - strToInt($plates[$i][$j])) < $minDiff) { $minDiff = abs($searchInt - strToInt($plates[$i][$j])); $minYear = $plates[$i][0]; $minKey = $plates[$i][$j]; } } } return [$minYear, $minKey]; } print_r(find('KHW'));
The code down below is by no means optimized, but it's rather a concept of how you might solve your problem. //Flatten out array (one dimension without years and ----) $flatten = array(); foreach($plates as $platevalues) { foreach($platevalues as $pv) { if ($pv != '---' && $pv != '----' && intval($pv) == 0) { //Create a string only if valid letters included in the $letters-array //This string is then added to the new array that is flattened out $pv2 = ''; for($i=0;$i<strlen($pv);$i++) { $letter = substr($pv,$i,1); if (in_array($letter, $letters) !== false) { $pv2 .= $letter; } } $flatten[] = $pv2; } } } //Do the search $search = 'GWN'; $search_result = ''; //Create a new search string based on first found in flattened //plates array (first G, then GW, then GWN) for($i=0;$i<strlen($search);$i++) { foreach($flatten as $key=>$f) { if (substr($search,0,$i+1) == substr($f,0,$i+1)) { $search_result .= substr($search,$i,1); break; } } } /* $search_result is: GW */ //Create a new array where all items that begins with GW are included $result = []; foreach($flatten as $key=>$item) { if (substr($search_result,0,strlen($search_result)) == substr($item,0,strlen($search_result))) { $result[] = $item; } } /* $result = array (size=2) 0 => string 'GWC' (length=3) 1 => string 'GWV' (length=3) */ //Create an array with total ASCII-value for each item //in the $result array above $result_o = []; foreach($result as $item) { $o = 0; for($i=0;$i<strlen($item);$i++) { $o += ord(substr($item,$i,1)); } $result_o[]= $o; } /* $result_o = array (size=2) 0 => int 225 1 => int 244 */ //Get the total ASCII-value for the original search string $search_o = 0; for($i=0;$i<strlen($search);$i++) { $search_o += ord(substr($search,$i,1)); } /* $search_ o = 236 */ //Find closest value in the $result_o (ASCII) - array compared (225,244) //to the original $search_o ASCII value above (236) $closest = 0; $use_key = 0; foreach($result_o as $key=>$item) { if ($closest == 0 || abs($search_o - $closest) > abs($item - $search_o)) { $closest = $item; $use_key = $key; } } /* $closest = 244 (it's closer to 236 than 225 is) $use_key = 1 */ To get the result you have: /* $result = array (size=2) 0 => string 'GWC' (length=3) 1 => string 'GWV' (length=3) */ //This should print out GWV echo 'result=' . $result[$use_key];
Convert my script in recursive way?
I have script who searches closest searched number. So for example, let say that in array are this numbers: '0' => 1.72 '0.25' => 1.92 '0.75'=> 2.35 '1' => 3.00 I am searching for 0.50 handicap, so 0.25 and 0.75 are in same range from 0.50. In this situations i want to get greater number, what is 0.75 in this example. Code what works is this: function getClosest($search, $arr) { $closest = null; $num_arr = array(); $odd = 0.00; $i = 0; foreach ($arr as $handicap=>$item) { //first closest number if ($closest === null || abs($search - $closest) > abs($handicap - $search)) { $closest = $handicap; $odd = $item; } else{ $num_arr[$handicap] = $item; } } $newclosest = null; $newodd = 0.00; foreach($num_arr as $handicap=>$newitem){ //second closest number if ($newclosest === null || abs($search - $closest) > abs($handicap - $search)) { $newclosest = $handicap; $newodd = $newitem; } } //if difference between first and second number are same if(abs($search - $closest) == abs($newclosest - $search)){ if($newclosest > $closest){ //if second number is greater than first $closest = $newclosest; $odd = $newodd; } } return array('handicap'=>$closest,'odd'=>$odd); } I see that i can use recursion here, but i am not experienced in using recursion. I know that i need call it inside like this: $rec_arr = getClosest($num_arr,$search); but i get blank page even i dump function output.
use array_map function, $data = array('0'=>1.72,'0.75'=> 2.35,'0.25'=>1.92,'1' => 3.00); $v = 0.5; // search value $x = null; // difference value $y = array(); // temporary array array_map(function($i)use($data,$v,&$x,&$y){ if(isset($x)){ if($x > abs($i-$v)){ // if difference value is bigger than current $x = abs($i-$v); $y = array($i=>$data[$i]); }else if($x == abs($i-$v)){ // if difference value is same $key = array_keys($y); $y = $key[0] < $i ? array($i=>$data[$i]) : $y; } }else{ // first loop $x = abs($i-$v); $y = array($i=>$data[$i]); } },array_keys($data)); print_r($y); // result output Array ( [0.75] => 2.35 ), hope this help you.
//$a is array to be searched //$s is search key //$prev_key and $next_key will be output required $a = array('0'=>1,'0.25'=>123,'0.75'=>456,'0.78'=>456,'1'=>788); $s = '0'; if(isset($a[$s])){ echo $s; } else{ reset($a);//good to do while(key($a) < $s){ next($a); } $next_key = key($a); prev($a); $prev_key = key($a); echo $prev_key.'-'.$next_key; } The above code uses array internal pointers. I think this may help you.. source: https://stackoverflow.com/a/4792770/3202287
How to express an integer as the sum of powers-of-two?
I have this number: 0101 and I know it is the binary sum of 0100 0001 How can I get those values from the first one? EDIT I have create a snippet of code based on the logic by JoeCortopassi. The snippet its this: protected function _getSitesPublished($value) { static $bits = null; if (!$bits) { $bits = array (); $bit = 0; $x = 0; while ($bit < 4294967295) { $bit = pow (2, $x); $bits [$bit] = $bit; ++ $x; } } $sites = array (); foreach ($bits as $bit) { if (($value & $bit) == $bit) { $sites [] = $bit; } } return $sites; } It only create the bits the first time the method its called. I have to make the comprobation if (($value & $bit) == $bit) since $value & $bit will return an int (may be other than 0, as in 6 & 3) and because of that I can't use only if ($value & $bit) Thanks to all for your help. EDIT 2 Oops! I had a little bug... forgot to increase the $x XD
$values = bindec('0101'); $bar = 1; // 0001 $fizz = 2; // 0010 $foo = 4; // 0100 $baz = 8; // 1000 if ( $values & $bar ) { //returns true } if ( $values & $fizz ) { //returns false } if ( $values & $foo ) { //returns true } if ( $values & $baz ) { //returns false } EDIT: Is this more of what you're looking for? Not able to run it right now to test, but it should convey the message: function bitCheck($original, $num, $return) { if ( $num == 0 ) { return $return; } if ($original & $num) { $return[] = $num; } return bitCheck($original, $num-1,$return); }
Using JoeCortopassi's code: $value= bindec($binary); $sums=array(); $counter=1; while($counter<=$value){ if($counter & value) $sums[]=$counter; $counter*=2; } print_r($sums);
A Mathematica solution: k[number_] := ReplacePart[ConstantArray[0, Length#number], # -> 1] & /# (Position[number, 1] // Flatten) Gives a list of the single bit components of the binary input: (* k[{1, 0, 1, 1, 0}] -> {{1, 0, 0, 0, 0}, {0, 0, 1, 0, 0}, {0, 0, 0, 1, 0}} *) A Mathematica solution which takes a list of binary digits and returns a list of digit values. Clear[s]; Options[s] := {Base -> 2, Totalled -> False}; s[number_, OptionsPattern[]] := With[{digitVals = Reverse#Flatten# NestList[# OptionValue#Base &, {1}, Length#number - 1] number}, If[OptionValue#Totalled, Total#digitVals, digitVals]] (* s[{1, 0, 1, 0, 1}] -> {16, 0, 4, 0, 1} *)
The following works in java, which you could use similar logic in php or mathematica: public class IntAsPowerOfTwo { public static void main(String[] args) { printIntAsSumPowerOf2(256); printIntAsSumPowerOf2(15); printIntAsSumPowerOf2(-1023); } /** * Prints an integer as sum of powers of 2. * * #param valueToEvaluate */ public static void printIntAsSumPowerOf2(int valueToEvaluate) { if (valueToEvaluate < 0) { System.out.println("Integer to evaluate must be non negative."); } int runningValue = valueToEvaluate; int currPower = 0; // Increase until larger than current value. while (Math.pow(2, currPower) < runningValue) { currPower++; } // Output sum of power of 2s. boolean firstOutput = true; while (currPower >= 0) { if (runningValue >= Math.pow(2, currPower)) { if (firstOutput) { System.out.print(valueToEvaluate + " = 2^" + currPower); firstOutput = false; } else { System.out.print(" + 2^" + currPower); } runningValue = runningValue - (int) Math.pow(2, currPower); } currPower--; } System.out.print("\n"); } }