Dictionary from CSV (PHP) - php
I need to write a function that takes temperature as an input and returns a dictionary with years as keys and number of days as values.
CSV file (year, month, day, hour, temperature):
2019,1,1,0,0.1
2019,1,1,1,0.4
2019,1,1,2,0.8
2019,1,1,3,1.3
2019,1,1,4,1.8
...
2020,1,1,0,-3.9
The number of days is calculated by another function which I already have. It takes a year and a temperature and returns how many days in a given year the temperature was equal to or below the given temperature. Since the data is about hours, not days, the number of hours is found and then divided by 24.
The function:
function getDaysUnderTemp(int $targetYear, float $targetTemp): float {
$file = fopen("data/temperatures-filtered.csv", "r");
$hours = 0;
while ($data = fgetcsv($file)) {
if ($data[0] == $targetYear and $data[4] <= $targetTemp) {
$hours ++;
}
}
fclose($file);
return $hours / 24;
}
So as an example getDaysUnderTemp(2019, -10) returns 13.92.
This is a function I am asking about as I'm not sure how it might be done:
function getDaysUnderTempDictionary(float $targetTemp): array {
$file = fopen("data/temperatures-filtered.csv", "r");
while ($data = fgetcsv($file)) {
???
}
fclose($file);
return [];
}
The problem is I don't understand how an already written function could be implemented in this new one, and then create a required dictionary from all this data.
Desired output:
getDaysUnderTempDictionary(-10);
Array
(
[2019] => 3.88
[2020] => 0.21
[2021] => 13.92
)
If I were doing this, I would read all the data into an array in raw form
then produce whatever other structures I needed.
I am going to write this as a class:
class TempCalculator {
private $data;
private $arr;
const YEAR = 0;
const TEMP = 4;
public function __construct($filename) {
$this->data = array_map('str_getcsv', file($filename));
}
public function getHoursBelowTemperature($temperature) : array {
$this->arr = array();
foreach ($this->data as $row) {
$year = $row[self::YEAR];
$temperatureValue = floatval($row[self::TEMP]);
if ($temperatureValue < $temperature) {
if (!array_key_exists($year, $this->arr)) {
$this->arr[$year] = 0;
}
$this->arr[$year]++;
}
}
// Walk the array and divide all the hours by 24
array_walk($this->arr, function (&$value) {
$value /= 24;
});
return $this->arr;
}
public getDaysUnderTemp($year, $temp) : float {
$hours = 0;
foreach ($this->data as $row) {
if ($row[self::YEAR] == $targetYear && $row[self::TEMP] <= $targetTemp) {
$hours ++;
}
}
return $hours / 24;
}
}
You can call it like this:
$tempCalculator = new TempCalculator('temperatures.csv');
$result = $tempCalculator->getHoursBelowTemperature(0);
print_r($result);
$result2 = $tempCalculator->getDaysUnderTemp(1.5);
print_r($result);
Related
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];
Parsing time format
How do I calculate the input to time in seconds, when the input is in different formats as shown in the example output below? With this format, all parts are optional: 5d 4h 3m 2s -> 5 days, 4 hours, 3 minutes and 2 seconds 4h 2s -> 4 hours and 2 seconds 3m -> 3 minutes With this format, parts are sometimes optional: 05: 04: 03: 02 -> 5 days, 4 hours, 3 minutes and 2 seconds 4:03:02 -> 4 hours, 3 minutes and 2 seconds 05: 00: 03: 02 -> 5 days, 3 minutes and 2 seconds 02 -> 2 seconds I'd like to get this output: > php time.php 1d 6h 20m 2s > 109.202 seconds > php time.php 3:50 > 230 seconds > php time.php 4: 23: 45: 02 > 431.102 seconds > php time.php 23m > 1.380 seconds So far I made it possible to convert input seconds to a time format, but after 5 hours of trying to make the above question work I kind of gave up: <?php $setTime = $argv[1]; function format_time($t,$f=':') { return sprintf("%02d%s%02d%s%02d", floor($t/3600), $f, ($t/60)%60, $f, $t%60); } echo format_time($setTime); ?>
You could use preg_match_all to split the input into pairs of numbers and suffixes and then iterate those to count the number of seconds: function seconds($input) { preg_match_all("/(\d+)(\S)/", "$input:", $matches, PREG_SET_ORDER); $letters = "smhd"; $durations = ["s" => 1, "m" => 60, "h" => 60*60, "d" => 60*60*24]; $seconds = 0; foreach (array_reverse($matches) as list($all, $num, $code)) { $i = strpos($letters, $code); if ($i === false) $code = $letters[$i = 0]; $letters = substr($letters, $i+1); $seconds += $durations[$code] * $num; } return $seconds; } function test($input) { $seconds = number_format(seconds($input)); echo "$input => $seconds seconds\n"; } test("1d 6h 20m 2s"); // 109.202 seconds test("3:50"); // 230 seconds test("4: 23: 45: 02"); // 431.102 seconds test("23m"); // 1.380 seconds 3v4l.org demo
The following might be total overkill, but it also might illustrate how you can approach this problem if you want your code to be extendable and easy to reuse: <?php declare(strict_types=1); error_reporting(-1); ini_set('display_errors', 'On'); interface TimeStringParser { public function accepts(string $input): bool; public function parse(string $input): int; } final class InputWithUnits implements TimeStringParser { public function accepts(string $input): bool { foreach (preg_split('/\s+/', $input) as $chunk) { if (! preg_match('/^\d+(d|h|m|s)$/', $chunk)) { return false; } } return true; } public function parse(string $input): int { if (! $this->accepts($input)) { throw new \InvalidArgumentException('Invalid input.'); } $result = 0; if (preg_match_all('/((?<value>\d+)(?<unit>d|h|m|s))/', $input, $matches)) { foreach ($matches['unit'] as $i => $unit) { $value = (int) $matches['value'][$i]; switch ($unit) { case 'd': $result += $value * 86400; break; case 'h': $result += $value * 3600; break; case 'm': $result += $value * 60; break; case 's': $result += $value * 1; break; } } } return $result; } } final class InputWithoutUnits implements TimeStringParser { public function accepts(string $input): bool { foreach (explode(':', $input) as $chunk) { if (! preg_match('/^\d+$/', trim($chunk))) { return false; } } return true; } public function parse(string $input): int { if (! $this->accepts($input)) { throw new \InvalidArgumentException('Invalid input.'); } $multiplier = [1, 60, 3600, 86400]; $result = 0; foreach (array_reverse(explode(':', $input)) as $chunk) { $value = (int) trim($chunk); $result += $value * array_shift($multiplier); } return $result; } } final class ParserComposite implements TimeStringParser { private $parsers; public function __construct(TimeStringParser ...$parsers) { $this->parsers = $parsers; } public function accepts(string $input): bool { foreach ($this->parsers as $parser) { if ($parser->accepts($input)) { return true; } } return false; } public function parse(string $input): int { foreach ($this->parsers as $parser) { if ($parser->accepts($input)) { return $parser->parse($input); } } throw new \InvalidArgumentException('Invalid input.'); } } $parser = new ParserComposite( new InputWithUnits(), new InputWithoutUnits() ); $testCases = [ '5d 4h 3m 2s', '4h 2s', '3m', '05: 04: 03: 02', '4:03:02', '05: 00: 03: 02', '02', '23m', '2e-5' ]; foreach ($testCases as $testCase) { if ($parser->accepts($testCase)) { printf("%-'.20s: %8d\n", $testCase, $parser->parse($testCase)); } else { printf("%-'.20s: unsupported\n", $testCase); } } https://3v4l.org/qAYqD
How to find backward primes within a range of integers?
I'm trying to solve a backward prime question. Following is the question: Find all Backwards Read Primes between two positive given numbers (both inclusive), the second one being greater than the first one. The resulting array or the resulting string will be ordered following the natural order of the prime numbers. Example backwardsPrime(2, 100) => [13, 17, 31, 37, 71, 73, 79, 97] backwardsPrime(9900, 10000) => [9923, 9931, 9941, 9967] I tried doing something like this: public function backwardPrime() { $start = 7000; $stop = 7100; $ans = []; while($start <= $stop) { if($start > 10) { if($start !== $this->reverse($start)) { if($this->isPrime($start) && $this->isPrime($this->reverse($start))) { array_push($ans, $start); } } } $start++; } return $ans; } public function reverse($num) { $reverse = 0; while($num > 0) { $reverse = $reverse * 10; $reverse = $reverse + $num%10; $num = (int)($num/10); } return $reverse; } public function isPrime($num) { if($num == 1 || $num == 2 || $num == 3) return true; elseif ($num%2 == 0 || $num%3 == 0) return false; else { $i=5; while($i<=$num/2) { if($num%$i===0) { return false; } $i++; } } return true; } I'm able to get the appropriate answer but while doing the same in single function I'm not able to get it: public function backwardPrimes() { $start = 7000; $stop = 7100; $ans = []; while($start <= $stop) { $isStartPrime = true; $isReversePrime = true; if($start > 10) { $reverse = 0; $num = $start; while($num > 0) { $reverse = $reverse * 10; $reverse = $reverse + $num%10; $num = (int)($num/10); } if($start !== $reverse) { if($start%2 != 0 && $start%3 != 0) { $i =5; while($i<=$start/2) { if($start%$i === 0) { $isStartPrime = false; break; } $i++; } } if($reverse%2 != 0 && $reverse%3 != 0) { $i =5; while($i<=$reverse/2) { if($reverse%$i === 0) { $isReversePrime = false; break; } $i++; } } if($isStartPrime && $isReversePrime) { array_push($ans, $start); } } } $start++; } return $ans; } I don't know where I'm having mistake, guide me. Thanks.
An emirp ("prime" spelled backwards) is a prime whose (base 10) reversal is also prime, but which is not a palindromic prime. in other words Backwards Read Primes are primes that when read backwards in base 10 (from right to left) are a different prime. (This rules out primes which are palindromes.) try this short solution in which I use two helper function reverse and isPrime : isPrime: Thanks to #Jeff Clayton for his method to test prime numbers, for more information click the link below https://stackoverflow.com/a/24769490/4369087 reverse: that use the php function [strrev()][1], this method take a string a reverse it, we'll use this trick to reverse a number by converting it to a string reverse it and converting back to an integer. backwardsPrime: this last function's job is itterating over a range of numbers from $min value to $max value and test if the number if a prime number and it's reverse is a prime number as well and it's not a palindrome number if all of those conditions are true then we addit to the result array. implementation function isPrime($number) { return !preg_match('/^1?$|^(11+?)\1+$/x', str_repeat('1', $number)); } function reverse($n) { return (int) strrev((string) $n); } function backwardsPrime($min, $max) { $result = []; foreach(range($min, $max) as $number) { $reverse = reverse($number); if($reverse !== $number && isPrime($number) && isPrime($reverse)) { $result[] = $number; } } return $result; } echo "<pre>"; print_r(backwardsPrime(2, 100)); print_r(backwardsPrime(9900, 10000)); output : Array ( [0] => 13 [1] => 17 [2] => 31 [3] => 37 [4] => 71 [5] => 73 [6] => 79 [7] => 97 ) Array ( [0] => 9923 [1] => 9931 [2] => 9941 [3] => 9967 ) you can even optimize the backwardsPrime function like this : function backwardsPrime($min, $max) { $result = []; foreach(range($min, $max) as $number) { $reverse = reverse($number); if($reverse !== $number && !in_array($number, $result) && isPrime($number) && isPrime($reverse)) { $result[] = $number; } } return $result; }
Loop and AND conditional clause
I have had a hard time to get my head around this little piece of code. protected function compressLowest($lowest){ $result = array(); $result['morning'] = array(); $result['afternoon'] = array(); $result['evening'] = array(); $result['allDay'] = array(); $type = $this->prices->getCondType(); $lastDate = 0; $i = array(); $i['morning'] = $i['afternoon'] = $i['evening'] = $i['allDay'] = 0; foreach($lowest as $date => $prices){ foreach($prices as $range => $price) { if($this->isNextDay($date, $result[$range][$i[$range]]['to']) && $result[$range][$i[$range]]['price'] == $price){ $result[$range][$i[$range]]['to'] = $date; } else { $i[$range] = count($result[$range]); $result[$range][] = array(); $result[$range][$i[$range]]['from'] = $date; $result[$range][$i[$range]]['to'] = $date; $result[$range][$i[$range]]['price'] = $price; $result[$range][$i[$range]]['destime']=$this->arr['destime']; $result[$range][$i[$range]]['deptime']=$this->arr['deptime']; $result[$range][$i[$range]]['flight']=$this->arr['flight']; } } $lastDate = $date; } //print_r($result);exit(); return $result; } And IsNextDay is checked as follows protected function isNextDay($next, $day){ if($next - $day == 86400){ //60*60*24 = 86400 return true; } else { return false; } } I can't figure out what is isNextDay($date, $result[$range][$i[$range]]['to']) && $result[$range][$i[$range]]['price'] == $price) supposed to mean (the $day thing)? in the if conditional clause of the second for-loop in the above function. Thank you if you could help me understand. UPDATE *Sorry I hadn't read it carefully until I discovered there was ) after the result[][]['to']... thanks for your concern.* For the source code above, I always have a notice of UNDEFINED OFFSET 0. How to fix this bug-to-be ?
for your Undefined Offset 0 at the if line some index evaluates to 0 and the array you are using that index on does not have an element at that index. For instance (I won't list all the possibilities) if $range is 0 and $result[0] is non-existent.