draw line with php using coordinates from txt file - php

I have file A2.txt with coordinate x1,y1,x2,y2 in every line like below :
204 13 225 59
225 59 226 84
226 84 219 111
219 111 244 192
244 192 236 209
236 209 254 223
254 223 276 258
276 258 237 337
in my php file i have that code. This code should take every line and draw line with coordinate from line. But something was wrong cause nothing was draw :/:
<?php
$plik = fopen("A2.txt", 'r') or die("blad otarcia");
while(!feof($plik))
{
$l = fgets($plik,20);
$k = explode(' ',$l);
imageline ( $mapa , $k[0] , $k[1] , $k[2] , $k[3] , $kolor );
}
imagejpeg($mapa);
imagedestroy($mapa);
fclose($plik) ;
?>
If I use imagejpeg and imagedestroy in while its only first line draw. What to do to draw every line ??
Please help :)

Unstructured, no cleanup or error checking example:
<?php
$plik = <<<EOD
204 13 225 59
225 59 226 84
226 84 219 111
219 111 244 192
244 192 236 209
236 209 254 223
254 223 276 258
276 258 237 337
EOD;
$plik = preg_replace('/\r\n?/', "\n", $plik);
$arr = explode("\n", $plik);
array_walk($arr,
function (&$value, $key) {
$value = explode(' ', $value);
}
);
$minwidth = array_reduce($arr,
function ($res, $val) { return min($res, $val[0], $val[2]); },
PHP_INT_MAX);
$maxwidth = array_reduce($arr,
function ($res, $val) { return max($res, $val[0], $val[2]); },
(PHP_INT_MAX * -1) - 1);
$minheight = array_reduce($arr,
function ($res, $val) { return min($res, $val[1], $val[3]); },
PHP_INT_MAX);
$maxheight = array_reduce($arr,
function ($res, $val) { return max($res, $val[1], $val[3]); },
(PHP_INT_MAX * -1) - 1);
/* note: The image does not reflect the "+ 1"'s I added in a subsequent edit */
$mapa = imagecreatetruecolor($maxwidth - $minwidth + 1, $maxheight - $minheight + 1);
$kolor = imagecolorallocate($mapa, 100, 200, 50);
foreach ($arr as $k) {
imageline($mapa,
$k[0] - $minwidth,
$k[1] - $minheight,
$k[2] - $minwidth,
$k[3] - $minheight, $kolor );
}
header("Content-type: image/png");
imagepng($mapa);
result:

Related

How to print all possible variations without repetitions of array for given range?

This is what I got:
<?php
// Program to print all
// combination of size r
// in an array of size n
function printCombinations($arr, $n, $r) {
$data = [];
combinationUtil($arr, $data, 0, $n - 1, 0, $r);
}
function combinationUtil($arr, $data, $start, $end, $index, $r) {
if ($index == $r) {
for ($j = 0; $j < $r; $j++) {
echo $data[$j];
}
echo "<br>";
return;
}
for ($i = $start; $i <= $end && $end - $i + 1 >= $r - $index; $i++) {
$data[$index] = $arr[$i];
combinationUtil($arr, $data, $i + 1, $end, $index + 1, $r);
}
}
$arr = [
1,
2,
3,
4,
5
];
$r = 3;
$n = count($arr);
printCombinations($arr, $n, $r);
and it gives this output:
123
124
125
134
135
145
234
235
245
345
And what I need is this:
123
124
125
132
134
135
142
143
145
152
153
154
213
214
215
231
234
235
241
243
245
251
253
254
312
314
315
321
324
325
341
342
345
351
352
354
412
413
414
415
421
423
425
431
432
435
451
452
453
512
513
514
521
523
524
531
532
534
541
542
543
You can use a recursive approach, that iterates over the array, and calls itself in each iteration by removing the current element, and prepending the returned variations with it.
Something like this:
<?php
function variation_without_repetition ($array,$items){
if($items == 0 || count($array) == 0) return [[]];
$variations = [];
foreach($array as $index => $item){
if(array_search($item, $array) < $index) continue;
$array_remaining = $array;
array_splice($array_remaining,$index,1);
foreach(variation_without_repetition($array_remaining,$items - 1) as $variation){
array_unshift($variation,$item);
$variations[] = $variation;
}
}
return $variations;
}
$variations = variation_without_repetition([1,2,3,4,5], 3);
foreach($variations as $variation){
echo implode($variation);
echo "<br>\n";
}
?>

How to write the following switch case with less lines of code?

How do I write the following switch case code using less lines? It is taking up a lot of space and lines but I'm unsure what's the better way of writing this.
This is a function where I am calculating the price which I have set in WordPress backend according to the various distance range.
if the distance is less than 300 miles, I have a fixed rate set in the backend for various distance range and if it is greater than 300 miles, then I want to use price per mile. The code does exactly what I need but I feel there can be more compact way of writing this?
Thanks in advance!
Following is the code:
function calculatePrice($distance_value_complete, $fixed_rate, $variable_rate) {
if (floatval($distance_value_complete) < 300 ):
switch (true) {
case floatval($distance_value_complete) < 2:
$vehicle_price1 = $fixed_rate['upto_2_mile'];
break;
case ( (floatval($distance_value_complete) >= 2) && (floatval($distance_value_complete) < 4) ):
$vehicle_price1 = $fixed_rate['from_2_to_4_miles'];
break;
case ( (floatval($distance_value_complete) >= 4) && (floatval($distance_value_complete) < 9) ):
$vehicle_price1 = $fixed_rate['from_4_to_9_miles'];
break;
case ( (floatval($distance_value_complete) >= 9) && (floatval($distance_value_complete) < 14) ):
$vehicle_price1 = $fixed_rate['from_9_to_14_miles'];
break;
case ( (floatval($distance_value_complete) >= 14) && (floatval($distance_value_complete) < 19) ):
$vehicle_price1 = $fixed_rate['from_14_to_19_miles'];
break;
case ( (floatval($distance_value_complete) >= 19) && (floatval($distance_value_complete) < 25) ):
$vehicle_price1 = $fixed_rate['from_19_to_25_miles'];
break;
case ( (floatval($distance_value_complete) >= 25) && (floatval($distance_value_complete) < 29) ):
$vehicle_price1 = $fixed_rate['from_25_to_29_miles'];
break;
case ( (floatval($distance_value_complete) >= 29) && (floatval($distance_value_complete) < 35) ):
$vehicle_price1 = $fixed_rate['from_29_to_35_miles'];
break;
case ( (floatval($distance_value_complete) >= 35) && (floatval($distance_value_complete) < 40) ):
$vehicle_price1 = $fixed_rate['from_35_to_40_miles'];
break;
case ( (floatval($distance_value_complete) >= 40) && (floatval($distance_value_complete) < 45) ):
$vehicle_price1 = $fixed_rate['from_40_to_45_miles'];
break;
case ( (floatval($distance_value_complete) >= 45) && (floatval($distance_value_complete) < 50) ):
$vehicle_price1 = $fixed_rate['from_45_to_50_miles'];
break;
case ( (floatval($distance_value_complete) >= 50) && (floatval($distance_value_complete) < 56) ):
$vehicle_price1 = $fixed_rate['from_50_to_56_miles'];
break;
case ( (floatval($distance_value_complete) >= 56) && (floatval($distance_value_complete) < 62) ):
$vehicle_price1 = $fixed_rate['from_56_to_62_miles'];
break;
case ( (floatval($distance_value_complete) >= 62) && (floatval($distance_value_complete) < 70) ):
$vehicle_price1 = $fixed_rate['from_62_to_70_miles'];
break;
case ( (floatval($distance_value_complete) >= 70) && (floatval($distance_value_complete) < 80) ):
$vehicle_price1 = $fixed_rate['from_70_to_80_miles'];
break;
case ( (floatval($distance_value_complete) >= 80) && (floatval($distance_value_complete) < 90) ):
$vehicle_price1 = $fixed_rate['from_80_to_90_miles'];
break;
case ( (floatval($distance_value_complete) >= 90) && (floatval($distance_value_complete) < 100) ):
$vehicle_price1 = $fixed_rate['from_90_to_100_miles'];
break;
case ( (floatval($distance_value_complete) >= 100) && (floatval($distance_value_complete) < 110) ):
$vehicle_price1 = $fixed_rate['from_100_to_110_miles'];
break;
case ( (floatval($distance_value_complete) >= 110) && (floatval($distance_value_complete) < 120) ):
$vehicle_price1 = $fixed_rate['from_110_to_120_miles'];
break;
case ( (floatval($distance_value_complete) >= 120) && (floatval($distance_value_complete) < 130) ):
$vehicle_price1 = $fixed_rate['from_120_to_130_miles'];
break;
case ( (floatval($distance_value_complete) >= 130) && (floatval($distance_value_complete) < 140) ):
$vehicle_price1 = $fixed_rate['from_130_to_140_miles'];
break;
case ( (floatval($distance_value_complete) >= 140) && (floatval($distance_value_complete) < 150) ):
$vehicle_price1 = $fixed_rate['from_140_to_150_miles'];
break;
case ( (floatval($distance_value_complete) >= 150) && (floatval($distance_value_complete) < 160) ):
$vehicle_price1 = $fixed_rate['from_150_to_160_miles'];
break;
case ( (floatval($distance_value_complete) >= 160) && (floatval($distance_value_complete) < 170) ):
$vehicle_price1 = $fixed_rate['from_160_to_170_miles'];
break;
case ( (floatval($distance_value_complete) >= 170) && (floatval($distance_value_complete) < 180) ):
$vehicle_price1 = $fixed_rate['from_170_to_180_miles'];
break;
case ( (floatval($distance_value_complete) >= 180) && (floatval($distance_value_complete) < 190) ):
$vehicle_price1 = $fixed_rate['from_180_to_190_miles'];
break;
case ( (floatval($distance_value_complete) >= 190) && (floatval($distance_value_complete) < 200) ):
$vehicle_price1 = $fixed_rate['from_190_to_200_miles'];
break;
case ( (floatval($distance_value_complete) >= 200) && (floatval($distance_value_complete) < 210) ):
$vehicle_price1 = $fixed_rate['from_200_to_210_miles'];
break;
case ( (floatval($distance_value_complete) >= 210) && (floatval($distance_value_complete) < 220) ):
$vehicle_price1 = $fixed_rate['from_210_to_220_miles'];
break;
case ( (floatval($distance_value_complete) >= 220) && (floatval($distance_value_complete) < 230) ):
$vehicle_price1 = $fixed_rate['from_220_to_230_miles'];
break;
case ( (floatval($distance_value_complete) >= 230) && (floatval($distance_value_complete) < 240) ):
$vehicle_price1 = $fixed_rate['from_230_to_240_miles'];
break;
case ( (floatval($distance_value_complete) >= 240) && (floatval($distance_value_complete) < 250) ):
$vehicle_price1 = $fixed_rate['from_240_to_250_miles'];
break;
case ( (floatval($distance_value_complete) >= 250) && (floatval($distance_value_complete) < 260) ):
$vehicle_price1 = $fixed_rate['from_250_to_260_miles'];
break;
case ( (floatval($distance_value_complete) >= 260) && (floatval($distance_value_complete) < 270) ):
$vehicle_price1 = $fixed_rate['from_260_to_270_miles'];
break;
case ( (floatval($distance_value_complete) >= 270) && (floatval($distance_value_complete) < 280) ):
$vehicle_price1 = $fixed_rate['from_270_to_280_miles'];
break;
case ( (floatval($distance_value_complete) >= 280) && (floatval($distance_value_complete) < 290) ):
$vehicle_price1 = $fixed_rate['from_280_to_290_miles'];
break;
case ( (floatval($distance_value_complete) >= 290) && (floatval($distance_value_complete) < 300) ):
$vehicle_price1 = $fixed_rate['from_290_to_300_miles'];
break;
}
else:
switch (true) {
case floatval($distance_value_complete) >= 300:
$vehicle_price1 = floatval($distance_value_complete) * $variable_rate['from_300_and_above'];
break;
}
endif;
return $vehicle_price1;
}
Simply rather not use a switch in such cases, where you have to deal with complex comparison expressions:
<?php
function calculatePrice($distance_value_complete, $fixed_rate, $variable_rate)
{
$distance_completed = floatval($distance_value_complete);
static $minimum_distance = 2;
static $maximum_distance = 300;
if ($distance_completed >= $maximum_distance) {
return $distance_completed * $variable_rate['from_' . $maximum_distance . '_and_above'];;
}
if ($distance_completed < $minimum_distance) {
return $fixed_rate['upto_' . $minimum_distance . '_mile'];
}
static $fixed_distances = array(
4, 9, 14, 19, 25, 29, 35, 40, 45, 50, 56, 62, 70, 80, 90, 100,
110, 120, 130, 140, 150, 160, 170, 180, 190, 200,
210, 220, 230, 240, 250, 260, 270, 280, 290, 300
);
$last_distance = $minimum_distance;
foreach ($fixed_distances as $distance) {
if ($distance_completed < $distance) {
return $fixed_rate['from_' . $last_distance . '_to_' . $distance . '_miles'];
}
$last_distance = $distance;
}
// This should never happen, unless you modify $fixed_distances and forget to change the early return conditions
throw new \Exception(sprintf('Distance %f out of range', $distance_completed));
}
Test results:
0 = upto_2_mile
1 = upto_2_mile
2 = from_2_to_4_miles
3 = from_2_to_4_miles
4 = from_4_to_9_miles
5 = from_4_to_9_miles
6 = from_4_to_9_miles
7 = from_4_to_9_miles
8 = from_4_to_9_miles
9 = from_9_to_14_miles
10 = from_9_to_14_miles
11 = from_9_to_14_miles
12 = from_9_to_14_miles
13 = from_9_to_14_miles
14 = from_14_to_19_miles
15 = from_14_to_19_miles
16 = from_14_to_19_miles
17 = from_14_to_19_miles
18 = from_14_to_19_miles
19 = from_19_to_25_miles
20 = from_19_to_25_miles
21 = from_19_to_25_miles
22 = from_19_to_25_miles
23 = from_19_to_25_miles
24 = from_19_to_25_miles
25 = from_25_to_29_miles
26 = from_25_to_29_miles
27 = from_25_to_29_miles
28 = from_25_to_29_miles
29 = from_29_to_35_miles
30 = from_29_to_35_miles
31 = from_29_to_35_miles
32 = from_29_to_35_miles
33 = from_29_to_35_miles
34 = from_29_to_35_miles
35 = from_35_to_40_miles
36 = from_35_to_40_miles
37 = from_35_to_40_miles
38 = from_35_to_40_miles
39 = from_35_to_40_miles
40 = from_40_to_45_miles
41 = from_40_to_45_miles
42 = from_40_to_45_miles
43 = from_40_to_45_miles
44 = from_40_to_45_miles
45 = from_45_to_50_miles
46 = from_45_to_50_miles
47 = from_45_to_50_miles
48 = from_45_to_50_miles
49 = from_45_to_50_miles
50 = from_50_to_56_miles
51 = from_50_to_56_miles
52 = from_50_to_56_miles
53 = from_50_to_56_miles
54 = from_50_to_56_miles
55 = from_50_to_56_miles
56 = from_56_to_62_miles
57 = from_56_to_62_miles
58 = from_56_to_62_miles
59 = from_56_to_62_miles
60 = from_56_to_62_miles
61 = from_56_to_62_miles
62 = from_62_to_70_miles
63 = from_62_to_70_miles
64 = from_62_to_70_miles
65 = from_62_to_70_miles
66 = from_62_to_70_miles
67 = from_62_to_70_miles
68 = from_62_to_70_miles
69 = from_62_to_70_miles
70 = from_70_to_80_miles
71 = from_70_to_80_miles
72 = from_70_to_80_miles
73 = from_70_to_80_miles
74 = from_70_to_80_miles
75 = from_70_to_80_miles
76 = from_70_to_80_miles
77 = from_70_to_80_miles
78 = from_70_to_80_miles
79 = from_70_to_80_miles
80 = from_80_to_90_miles
81 = from_80_to_90_miles
82 = from_80_to_90_miles
83 = from_80_to_90_miles
84 = from_80_to_90_miles
85 = from_80_to_90_miles
86 = from_80_to_90_miles
87 = from_80_to_90_miles
88 = from_80_to_90_miles
89 = from_80_to_90_miles
90 = from_90_to_100_miles
91 = from_90_to_100_miles
92 = from_90_to_100_miles
93 = from_90_to_100_miles
94 = from_90_to_100_miles
95 = from_90_to_100_miles
96 = from_90_to_100_miles
97 = from_90_to_100_miles
98 = from_90_to_100_miles
99 = from_90_to_100_miles
100 = from_100_to_110_miles
101 = from_100_to_110_miles
102 = from_100_to_110_miles
103 = from_100_to_110_miles
104 = from_100_to_110_miles
105 = from_100_to_110_miles
106 = from_100_to_110_miles
107 = from_100_to_110_miles
108 = from_100_to_110_miles
109 = from_100_to_110_miles
110 = from_110_to_120_miles
111 = from_110_to_120_miles
112 = from_110_to_120_miles
113 = from_110_to_120_miles
114 = from_110_to_120_miles
115 = from_110_to_120_miles
116 = from_110_to_120_miles
117 = from_110_to_120_miles
118 = from_110_to_120_miles
119 = from_110_to_120_miles
120 = from_120_to_130_miles
121 = from_120_to_130_miles
122 = from_120_to_130_miles
123 = from_120_to_130_miles
124 = from_120_to_130_miles
125 = from_120_to_130_miles
126 = from_120_to_130_miles
127 = from_120_to_130_miles
128 = from_120_to_130_miles
129 = from_120_to_130_miles
130 = from_130_to_140_miles
131 = from_130_to_140_miles
132 = from_130_to_140_miles
133 = from_130_to_140_miles
134 = from_130_to_140_miles
135 = from_130_to_140_miles
136 = from_130_to_140_miles
137 = from_130_to_140_miles
138 = from_130_to_140_miles
139 = from_130_to_140_miles
140 = from_140_to_150_miles
141 = from_140_to_150_miles
142 = from_140_to_150_miles
143 = from_140_to_150_miles
144 = from_140_to_150_miles
145 = from_140_to_150_miles
146 = from_140_to_150_miles
147 = from_140_to_150_miles
148 = from_140_to_150_miles
149 = from_140_to_150_miles
150 = from_150_to_160_miles
151 = from_150_to_160_miles
152 = from_150_to_160_miles
153 = from_150_to_160_miles
154 = from_150_to_160_miles
155 = from_150_to_160_miles
156 = from_150_to_160_miles
157 = from_150_to_160_miles
158 = from_150_to_160_miles
159 = from_150_to_160_miles
160 = from_160_to_170_miles
161 = from_160_to_170_miles
162 = from_160_to_170_miles
163 = from_160_to_170_miles
164 = from_160_to_170_miles
165 = from_160_to_170_miles
166 = from_160_to_170_miles
167 = from_160_to_170_miles
168 = from_160_to_170_miles
169 = from_160_to_170_miles
170 = from_170_to_180_miles
171 = from_170_to_180_miles
172 = from_170_to_180_miles
173 = from_170_to_180_miles
174 = from_170_to_180_miles
175 = from_170_to_180_miles
176 = from_170_to_180_miles
177 = from_170_to_180_miles
178 = from_170_to_180_miles
179 = from_170_to_180_miles
180 = from_180_to_190_miles
181 = from_180_to_190_miles
182 = from_180_to_190_miles
183 = from_180_to_190_miles
184 = from_180_to_190_miles
185 = from_180_to_190_miles
186 = from_180_to_190_miles
187 = from_180_to_190_miles
188 = from_180_to_190_miles
189 = from_180_to_190_miles
190 = from_190_to_200_miles
191 = from_190_to_200_miles
192 = from_190_to_200_miles
193 = from_190_to_200_miles
194 = from_190_to_200_miles
195 = from_190_to_200_miles
196 = from_190_to_200_miles
197 = from_190_to_200_miles
198 = from_190_to_200_miles
199 = from_190_to_200_miles
200 = from_200_to_210_miles
201 = from_200_to_210_miles
202 = from_200_to_210_miles
203 = from_200_to_210_miles
204 = from_200_to_210_miles
205 = from_200_to_210_miles
206 = from_200_to_210_miles
207 = from_200_to_210_miles
208 = from_200_to_210_miles
209 = from_200_to_210_miles
210 = from_210_to_220_miles
211 = from_210_to_220_miles
212 = from_210_to_220_miles
213 = from_210_to_220_miles
214 = from_210_to_220_miles
215 = from_210_to_220_miles
216 = from_210_to_220_miles
217 = from_210_to_220_miles
218 = from_210_to_220_miles
219 = from_210_to_220_miles
220 = from_220_to_230_miles
221 = from_220_to_230_miles
222 = from_220_to_230_miles
223 = from_220_to_230_miles
224 = from_220_to_230_miles
225 = from_220_to_230_miles
226 = from_220_to_230_miles
227 = from_220_to_230_miles
228 = from_220_to_230_miles
229 = from_220_to_230_miles
230 = from_230_to_240_miles
231 = from_230_to_240_miles
232 = from_230_to_240_miles
233 = from_230_to_240_miles
234 = from_230_to_240_miles
235 = from_230_to_240_miles
236 = from_230_to_240_miles
237 = from_230_to_240_miles
238 = from_230_to_240_miles
239 = from_230_to_240_miles
240 = from_240_to_250_miles
241 = from_240_to_250_miles
242 = from_240_to_250_miles
243 = from_240_to_250_miles
244 = from_240_to_250_miles
245 = from_240_to_250_miles
246 = from_240_to_250_miles
247 = from_240_to_250_miles
248 = from_240_to_250_miles
249 = from_240_to_250_miles
250 = from_250_to_260_miles
251 = from_250_to_260_miles
252 = from_250_to_260_miles
253 = from_250_to_260_miles
254 = from_250_to_260_miles
255 = from_250_to_260_miles
256 = from_250_to_260_miles
257 = from_250_to_260_miles
258 = from_250_to_260_miles
259 = from_250_to_260_miles
260 = from_260_to_270_miles
261 = from_260_to_270_miles
262 = from_260_to_270_miles
263 = from_260_to_270_miles
264 = from_260_to_270_miles
265 = from_260_to_270_miles
266 = from_260_to_270_miles
267 = from_260_to_270_miles
268 = from_260_to_270_miles
269 = from_260_to_270_miles
270 = from_270_to_280_miles
271 = from_270_to_280_miles
272 = from_270_to_280_miles
273 = from_270_to_280_miles
274 = from_270_to_280_miles
275 = from_270_to_280_miles
276 = from_270_to_280_miles
277 = from_270_to_280_miles
278 = from_270_to_280_miles
279 = from_270_to_280_miles
280 = from_280_to_290_miles
281 = from_280_to_290_miles
282 = from_280_to_290_miles
283 = from_280_to_290_miles
284 = from_280_to_290_miles
285 = from_280_to_290_miles
286 = from_280_to_290_miles
287 = from_280_to_290_miles
288 = from_280_to_290_miles
289 = from_280_to_290_miles
290 = from_290_to_300_miles
291 = from_290_to_300_miles
292 = from_290_to_300_miles
293 = from_290_to_300_miles
294 = from_290_to_300_miles
295 = from_290_to_300_miles
296 = from_290_to_300_miles
297 = from_290_to_300_miles
298 = from_290_to_300_miles
299 = from_290_to_300_miles
300 = from_300_and_above
301 = from_300_and_above
302 = from_300_and_above
303 = from_300_and_above
304 = from_300_and_above
305 = from_300_and_above
306 = from_300_and_above
307 = from_300_and_above
308 = from_300_and_above
309 = from_300_and_above
310 = from_300_and_above
311 = from_300_and_above
312 = from_300_and_above
313 = from_300_and_above
314 = from_300_and_above
315 = from_300_and_above
316 = from_300_and_above
317 = from_300_and_above
318 = from_300_and_above
319 = from_300_and_above
320 = from_300_and_above
321 = from_300_and_above
322 = from_300_and_above
323 = from_300_and_above
324 = from_300_and_above
325 = from_300_and_above
326 = from_300_and_above
327 = from_300_and_above
328 = from_300_and_above
329 = from_300_and_above
330 = from_300_and_above
331 = from_300_and_above
332 = from_300_and_above
333 = from_300_and_above
334 = from_300_and_above
335 = from_300_and_above
336 = from_300_and_above
337 = from_300_and_above
338 = from_300_and_above
339 = from_300_and_above
340 = from_300_and_above
341 = from_300_and_above
342 = from_300_and_above
343 = from_300_and_above
344 = from_300_and_above
345 = from_300_and_above
346 = from_300_and_above
347 = from_300_and_above
348 = from_300_and_above
349 = from_300_and_above
350 = from_300_and_above```
Since you have a rate name depending on a single int value I would create an array that maps all the available rates, then pass it to a function with the value you are checking, something like this ( map is not complete, php7.2 required )
$conditionMap = [
[
'value' => 'upto_2_mile',
'condition' => '<2'
],
[
'value' => 'from_2_to_4_miles',
'condition' => '<4'
],
[
'value' => 'from_4_to_9_miles',
'condition' => '<9'
],
[
'value' => 'from_9_to_14_miles',
'condition' => '<14'
],
[
'value' => 'from_14_to_19_miles',
'condition' => '<19'
],
[
'value' => 'from_19_to_25_miles',
'condition' => '<25'
],
[
'value' => 'from_25_to_29_miles',
'condition' => '<29'
]
];
function getRate(int $value, array $conditionMap) : string {
$rate = 'Not found';
foreach ($conditionMap as $condition) {
$phpString = sprintf("return %s %s;", $value, $condition['condition']);
$evaluation = eval($phpString);
if($evaluation) {
$rate = $condition['value'];
break;
}
}
return $rate;
}
// TEST
for($i = 0; $i<=30; $i++) {
var_dump(sprintf("With value %s: %s", $i, getRate($i, $conditionMap)));
}
If you run this script you should obtain the result below
string(25) "With value 0: upto_2_mile"
string(25) "With value 1: upto_2_mile"
string(31) "With value 2: from_2_to_4_miles"
string(31) "With value 3: from_2_to_4_miles"
string(31) "With value 4: from_4_to_9_miles"
string(31) "With value 5: from_4_to_9_miles"
string(31) "With value 6: from_4_to_9_miles"
string(31) "With value 7: from_4_to_9_miles"
string(31) "With value 8: from_4_to_9_miles"
string(32) "With value 9: from_9_to_14_miles"
string(33) "With value 10: from_9_to_14_miles"
string(33) "With value 11: from_9_to_14_miles"
string(33) "With value 12: from_9_to_14_miles"
string(33) "With value 13: from_9_to_14_miles"
string(34) "With value 14: from_14_to_19_miles"
string(34) "With value 15: from_14_to_19_miles"
string(34) "With value 16: from_14_to_19_miles"
string(34) "With value 17: from_14_to_19_miles"
string(34) "With value 18: from_14_to_19_miles"
string(34) "With value 19: from_19_to_25_miles"
string(34) "With value 20: from_19_to_25_miles"
string(34) "With value 21: from_19_to_25_miles"
string(34) "With value 22: from_19_to_25_miles"
string(34) "With value 23: from_19_to_25_miles"
string(34) "With value 24: from_19_to_25_miles"
string(34) "With value 25: from_25_to_29_miles"
string(34) "With value 26: from_25_to_29_miles"
string(34) "With value 27: from_25_to_29_miles"
string(34) "With value 28: from_25_to_29_miles"
string(24) "With value 29: Not found"
string(24) "With value 30: Not found"

Matching the sum of values on string

I have a string of numerical values separated with spaces:
70 58 81 909 70 215 70 1022 580 930 898 70 276 31 11 **920 898** 1503 195 770 573 508 1015 31 8 815 1478 31 1022 31 1506 31 **318 500 358 865** 358 991 518 58 450 420 487 31 1478 108 70 1022 31 215 318 500 61 31 655 1061 918 54 898 31 8 1011 9 8 459 346 770 751 31 346 770 880 1171 688 1680 31 1002 769 500 61 8 702 898 8 1206 31 709 565 8 138 58 215 81 1171 31 288 500 380 70 284 1500 565 31 601 55 1501 490 565 530 56 990 380 1061 770 345 1171 31 55 1100 605 1471 1234 **31 470 725 358 114 56 9 55** 1100 1610 1471 1000 971 565 55 1100 1610 1061 770 345 949 31 370 52 688 1680 770 880 1171 163 249 151 489 653 56 990 380 503 490 770 1376 1056 31 8 64 490 565 55 108 56 1178 501 653 898 860 565 31 315 61 509 108 501 653 31 349 249 151 489 246 56 990 380 1070 573 1663 725 821 31 70 373 1171 490 565 55 108...
I want to get all occurrences of the string, where combined sum of numbers is x. So, if I search: 2041 it should return an array ("318 500 358 865") or if I search: 1818 it should return an array ("920 898", "31 470 725 358 114 56 9 55").
I also need solution to be optimal, because string of numbers can sum up to hundreds of thousands.
Principle explained in theory would be good, but preferred languages are PHP or NodeJs if solution is given by programming language. Even MySQL solution would be nice, if possible. But solution by any language would be nice anyway.
Extra notes
numbers are all positive integers
number values are between 1-10000
Usage:
$ex = new finder($string);
$result = $ex->search(979)->find(true); // true = Hard mode
First we pass the string we want to search, then we use method to_array() so we can create the array from the string, then you need to choose which mode you want to use.
It has 2 modes, soft search and hard search.
you can choose which one to use in the find method, ->find(true) , True = hard mode, False = soft mode;
The soft mode it is really simple, creates a new multidimensional array with keys as the strlen of the numbers (method order()), so if we are searching for a number 70 we don't really wanna use the 3 digits or more, i mean ( 100, 99999 etc... ). Then it just minus the search value with the number and tries to search in the entire array with (in_array) if it has the result;
foreach ($this->_clean as $clean) {
$minus = abs($clean - $search);
// Simple and fast query
if(in_array($minus, $this->_clean)){
$tmp[] = array($minus,$clean);
}
}
The hard mode is just as the name states, we will loop through every number.
public function hard_search($array, $partial){
$s = 0;
foreach ($partial as $x){
$s += $x;
}
if ($s == $this->_search){
$this->_tmp[] = $partial;
}
if ($s < $this->_search){
for($i=0;$i<count($array);$i++) {
$remaining = array();
$n = $array[$i];
for ($j=$i+1; $j<count($array); $j++) {
array_push($remaining, $array[$j]);
};
$partial_rec = $partial;
array_push($partial_rec, $n);
$this->hard_search($remaining,$partial_rec);
}
}
return $this->_tmp;
}
Of course we could really make a few more tweaks but from what i tested it gives good results.
Feel free to ask if you have any questions.
Example with outputs: http://codepad.viper-7.com/INvSNo
class finder {
public $stop;
protected $_string,
$_search,
$_tmp,
$_array = array(),
$_array_order = array(),
$_clean = array();
public function __construct($string){
$this->_string = $string;
}
/**
* String to array
*
* #return \find
*/
public function to_array(){
$this->_array = array_keys(
array_flip(
explode(' ', $this->_string)
)
);
return $this;
}
/**
* what we are searching for
*
* #param string/int $search
* #return \finder
*/
public function search($search){
$this->reset();
$this->_search = $search;
$this->to_array();
return $this;
}
/**
*
* #param type $a // array
* #param type $total // total
* #return array
*/
public function find($hard = false){
$this->_hard = $hard;
if(is_array($this->_search)){
foreach($this->_search as $search){
$result[] = $this->search_array($search);
}
}else{
$result = $this->search_array($this->_search);
}
return $result;
}
/**********************************
* SOFT SEARCH
***********************************/
/**
* Multidimensional Array with strlen as the key
*
* #return \find
*/
public function order(){
// Order
foreach($this->_array as $n){
$this->_array_order[strlen($n)][] = $n;
}
return $this;
}
public function clean($search){
$tmp = array();
$check_length = function($number) use($search){
if($number <= $search){
return $number;
}
return false;
};
foreach(range(key($this->_array_order), strlen($search)) as $v){
$tmp = array_map($check_length,array_merge($tmp, $this->_array_order[$v]));
}
$this->_clean = array_filter($tmp);
sort($this->_clean);
return $this;
}
public function search_array($search) {
$res = array();
if($this->_hard == false){
$this->order();
$this->clean($search);
$res = $this->soft_search($search);
}else{
$res = $this->hard_search($this->_array, array());
}
return $res;
}
/**
*
* #return array
*/
public function soft_search($search){
$tmp = array();
foreach ($this->_clean as $clean) {
$minus = abs($clean - $search);
// Simple and fast query
if(in_array($minus, $this->_clean)){
$tmp[] = array($minus,$clean);
}
}
return $tmp;
}
/**********************************
* END SOFT SEARCH
***********************************/
public function hard_search($array, $partial){
$s = 0;
foreach ($partial as $x){
$s += $x;
}
if ($s == $this->_search){
$this->_tmp[] = $partial;
}
// if higher STOP
if ($s < $this->_search){
for($i=0;$i<count($array);$i++) {
$remaining = array();
$n = $array[$i];
for ($j=$i+1; $j<count($array); $j++) {
array_push($remaining, $array[$j]);
};
$partial_rec = $partial;
array_push($partial_rec, $n);
$this->hard_search($remaining,$partial_rec);
}
}
return $this->_tmp;
}
/****************************
*
* Extra
*
*****************************/
public function reset(){
$this->_search = '';
$this->_clean = array();
$this->_array = array();
$this->_array_order = array();
$this->_tmp = array();
$this->_tmp = array();
return $this;
}
public function new_string($string){
$this->reset();
$this->_string = $string;
$this->to_array();
return $this;
}
}
$string = '70 58 81 909 70 215 130 70 1022 580 930 898 70 276 31 11 920 898 1503 195 770 573 508 '
. '1171 490 565 55 108';
$ex = new finder($string);
echo '<pre>';
echo '<h1>Hard 979</h1>';
$result = $ex->search(979)->find(true);
print_r($result);
echo '<h1>Soft 979</h1>';
$result = $ex->search(979)->find();
print_r($result);
echo '<h1>Hard 238</h1>';
$result = $ex->search(238)->find(true);
print_r($result);
echo '<h1>Soft 238</h1>';
$result = $ex->search(238)->find();
print_r($result);
Output example for 285:
Hard 285
Array
(
[0] => Array
(
[0] => 70
[1] => 215
)
[1] => Array
(
[0] => 58
[1] => 130
[2] => 31
[3] => 11
[4] => 55
)
)
Soft 285
Array
(
[0] => Array
(
[0] => 215
[1] => 70
)
)
Here you go, in Python. This has linear complexity:
def list2string( alist ):
return " ".join( map(str, alist ))
def string2list( s ):
return list(map( int, s.split() ))
def find_number( a, total ):
u = 0
y = 0 # the current sum of the interval (u .. v)
res = []
for v in range( 0, len(a) ):
# at this point the interval sum y is smaller than the requested total,
# so we move the right end of the interval forward
y += a[v]
while y >= total:
if y == total:
res.append( list2string( a[ u : v+1 ] ) )
# if the current sum is too large, move the left end of the interval forward
y -= a[u]
u += 1
return res
text = "70 58 81 909 70 215 70 1022 580 930 898"
alist = string2list(text)
print( find_number( alist, 285) )
I'm assuming there are no negative values in your list, and the list consists purely of integers separated by spaces. You shouldn't have any problems translating it into any other language. I hope the algorithm is self-explanatory, if not ask.

Finding and removing outliers in PHP

Suppose I sample a selection of database records that return the following numbers:
20.50, 80.30, 70.95, 15.25, 99.97, 85.56, 69.77
Is there an algorithm that can be efficiently implemented in PHP to find the outliers (if there are any) from an array of floats based on how far they deviate from the mean?
Ok let's assume you have your data points in an array like so:
<?php $dataset = array(20.50, 80.30, 70.95, 15.25, 99.97, 85.56, 69.77); ?>
Then you can use the following function (see comments for what is happening) to remove all numbers that fall outside of the mean +/- the standard deviation times a magnitude you set (defaults to 1):
<?php
function remove_outliers($dataset, $magnitude = 1) {
$count = count($dataset);
$mean = array_sum($dataset) / $count; // Calculate the mean
$deviation = sqrt(array_sum(array_map("sd_square", $dataset, array_fill(0, $count, $mean))) / $count) * $magnitude; // Calculate standard deviation and times by magnitude
return array_filter($dataset, function($x) use ($mean, $deviation) { return ($x <= $mean + $deviation && $x >= $mean - $deviation); }); // Return filtered array of values that lie within $mean +- $deviation.
}
function sd_square($x, $mean) {
return pow($x - $mean, 2);
}
?>
For your example this function returns the following with a magnitude of 1:
Array
(
[1] => 80.3
[2] => 70.95
[5] => 85.56
[6] => 69.77
)
For a normally distributed set of data, removes values more than 3 standard deviations from the mean.
<?php
function remove_outliers($array) {
if(count($array) == 0) {
return $array;
}
$ret = array();
$mean = array_sum($array)/count($array);
$stddev = stats_standard_deviation($array);
$outlier = 3 * $stddev;
foreach($array as $a) {
if(!abs($a - $mean) > $outlier) {
$ret[] = $a;
}
}
return $ret;
}
Topic: Detecting local, additive outliers in unordered arrays by walking a small window through the array and calculating the standard deviation for a certain range of values.
Good morning folks,
here is my solution much to late, but since I was looking for detecting outliers via PHP and could'nt find anything basic, I decided somehow smoothing a given dataset in a timeline of 24 h by simply moving a range of 5 items in a row through an unordered array and calculate the local standard deviation to detect the additive outliers.
The first function will simply calculate the average and deviation of a given array, where $col means the column with the values (sorry for the freegrades, this means that in an uncomplete dataset of 5 values you only have 4 freegrades - I don't know the exact english word for Freiheitsgrade):
function analytics_stat ($arr,$col,$freegrades = 0) {
// calculate average called mu
$mu = 0;
foreach ($arr as $row) {
$mu += $row[$col];
}
$mu = $mu / count($arr);
// calculate empiric standard deviation called sigma
$sigma = 0;
foreach ($arr as $row) {
$sigma += pow(($mu - $row[$col]),2);
}
$sigma = sqrt($sigma / (count($arr) - $freegrades));
return [$mu,$sigma];
}
Now its time for the core function, which will move through the given array and create a new array with the result. Margin means the factor to multiply the deviation with, since only one Sigma detects to many outliers, whereas more than 1.7 seems to high:
function analytics_detect_local_outliers ($arr,$col,$range,$margin = 1.0) {
$count = count($arr);
if ($count < $range) return false;
// the initial state of each value is NOT OUTLIER
$arr_result = [];
for ($i = 0;$i < $count;$i++) {
$arr_result[$i] = false;
}
$max = $count - $range + 1;
for ($i = 0;$i < $max;$i++) {
// calculate mu and sigma for current interval
// remember that 5 values will determine the divisor 4 for sigma
// since we only look at a part of the hole data set
$stat = analytics_stat(array_slice($arr,$i,$range),$col,1);
// a value in this interval counts, if it's found outside our defined sigma interval
$range_max = $i + $range;
for ($j = $i;$j < $range_max;$j++) {
if (abs($arr[$j][$col] - $stat[0]) > $margin * $stat[1]) {
$arr_result[$j] = true;
// this would be the place to add a counter to isolate
// real outliers from sudden steps in our data set
}
}
}
return $arr_result;
}
And finally comes the test function with random values in an array with length 24.
As for margin I was curious and choose the Golden Cut PHI = 1.618 ... since I really like this number and some Excel test results have led me to a margin of 1.7, above which outliers very rarelly were detected. The range of 5 is variable, but for me this was enough. So for every 5 values in a row there will be a calculation:
function test_outliers () {
// create 2 dimensional data array with items [hour,value]
$arr = [];
for ($i = 0;$i < 24;$i++) {
$arr[$i] = [$i,rand(0,500)];
}
// set parameter for detection algorithm
$result = [];
$col = 1;
$range = 5;
$margin = 1.618;
$result = analytics_detect_local_outliers ($arr,$col,$range,$margin);
// display results
echo "<p style='font-size:8pt;'>";
for ($i = 0;$i < 24;$i++) {
if ($result[$i]) echo "♦".$arr[$i][1]."♦ "; else echo $arr[$i][1]." ";
}
echo "</p>";
}
After 20 calls of the test function I got these results:
417 140 372 131 449 26 192 222 320 349 94 147 201 ♦342♦ 123 16 15
♦490♦ 78 190 ♦434♦ 27 3 276
379 440 198 135 22 461 208 376 286 ♦73♦ 331 358 341 14 112 190 110 266
350 232 265 ♦63♦ 90 94
228 ♦392♦ 130 134 170 ♦485♦ 17 463 13 326 47 439 430 151 268 172 342
445 477 ♦21♦ 421 440 219 95
88 121 292 255 ♦16♦ 223 244 109 127 231 370 16 93 379 218 87 ♦335♦ 150
84 181 25 280 15 406
85 252 310 122 188 302 ♦13♦ 439 254 414 423 216 456 321 85 61 215 7
297 337 204 210 106 149
345 411 308 360 308 346 ♦451♦ ♦77♦ 16 498 331 160 142 102 ♦496♦ 220
107 143 ♦241♦ 113 82 355 114 452
490 222 412 94 2 ♦480♦ 181 149 41 110 220 ♦477♦ 278 349 73 186 135 181
♦39♦ 136 284 340 165 438
147 311 246 449 396 328 330 280 453 374 214 289 489 185 445 86 426 246
319 ♦30♦ 436 290 384 232
442 302 ♦436♦ 50 114 15 21 93 ♦376♦ 416 439 ♦222♦ 398 237 234 44 102
464 204 421 161 330 396 461
498 320 105 22 281 168 381 216 435 360 19 ♦402♦ 131 128 66 187 291 459
319 433 86 84 325 247
440 491 381 491 ♦22♦ 412 33 273 256 331 79 452 314 485 66 138 116 356
290 190 336 178 298 218
394 439 387 ♦80♦ 463 369 ♦104♦ 388 465 455 ♦246♦ 499 70 431 360 ♦22♦
203 280 241 319 ♦34♦ 238 439 497
485 289 249 ♦416♦ 228 166 217 186 184 ♦356♦ 142 166 26 91 70 ♦466♦ 177
357 298 443 307 387 373 209
338 166 90 122 442 429 499 293 ♦41♦ 159 395 79 307 91 325 91 162 211
85 189 278 251 224 481
77 196 37 326 230 281 ♦73♦ 334 159 490 127 365 37 57 246 26 285 468
228 181 74 ♦455♦ 119 435
328 3 216 149 217 348 65 433 164 473 465 145 341 112 462 396 168 251
351 43 320 123 181 198
216 213 249 219 ♦29♦ 255 100 216 181 233 33 47 344 383 ♦94♦ 323 440
187 79 403 139 382 37 395
366 450 263 160 290 ♦126♦ 304 307 335 396 458 195 171 493 270 434 222
401 38 383 158 355 311 150
402 339 382 97 125 88 300 332 250 ♦86♦ 362 214 448 67 114 ♦354♦ 140 16
♦354♦ 109 0 168 127 89
450 5 232 155 159 264 214 ♦416♦ 51 429 372 230 298 232 251 207 ♦322♦
160 148 206 293 446 111 338
I hope, this will help anyone in the present or future.
Greetings
P.S. To further improve this algorithm you may add a counter, which makes sure, that a certain value must for instance be found at least 2 times, that means in 2 different intervals or windows, before it is labeled as outlier. So a sudden jump of the following values does not make the first value the villain. Let me give you an example:
In 3,6,5,9,37,40,42,51,98,39,33,45 there is an obvious step from 9 to 37 and an isolated value 98. I would like to detect 98, but not 9 or 37.
The first interval 3,6,5,9,37 would detect 37, the second interval 6,5,9,37,40 not. So we would not detect 37, since there is only one problematic interval or one match. Now it should be clear, that 98 counts in 5 intervals and is therefore an outlier. So lets declare a value an outlier, if it "counts" at least 2 times.
Like so often we have to look closely the borders, since they have only one interval, and make for these values an exception.

PHP: echoing a few selected lines of a txt file

I need to echo only selected lines from a .txt file using PHP.
The txt file content looks like this:
1 111 111 111 111 111 111 111 111 111 111
2 196 182 227 190 195 196 278 197 323 265
3 84.1 84.1 84.1 84.2 85.4 84.1 84.2 84.1 84.1 84.1
4 107 107 107 107 107 107 107 107 107 107
5 10.0 9.29 9.86 9.90 9.57 9.56 9.52 9.55 10.0 9.62
6 0.652 0.622 0.676 0.617 0.637 0.617 0.563 0.601 0.586 0.601
7 132 132 132 132 132 132 481 132 132 132
8 113 113 113 113 113 113 113 113 113 113
9 510 571 604 670 647 667 656 257 264 431
10 245 246 247 246 246 245 247 246 247 247
The previous working code was echoing every lines.
$fp = fopen("http://xxx/myfile.txt","r");
while (!feof($fp)) {
$page .= fgets($fp, 4096);
}
fclose($fp);
echo $page;
break;
I'm trying to get the same formating but only with the selected lines.
For instance let say only lines: 3, 5, 8, 10.
The second step would then be if the lines could be echoed in a different order than the initial one.
If someone knows a simple way to do it, that would be excellent!
Thanx in advance.
$lines = file('http://xxx/myfile.txt');
print $lines[2]; // line 3
print $lines[4]; // line 5
...
see file()
here's an example of how it can be done:
function echo_selected_lines_of_file($file, array $lines)
{
$fContents = file_get_contents($file); // read the file
$fLines = explode("\n", $fContents); // split the lines
foreach($fLines as $key=>$fLine) // foreach line...
if(in_array($key, $lines)) //if its in the $lines array, print it
echo $fLine.'<br>';
}
echo_selected_lines_of_file('index.php', array(1,4,7));
You could use the file() which converts each line into a array. But if your file is big it will consume a bit of memory.
$lines_to_print = [1,3,5,8];
$lines = file('file.txt');
for($i in $line_to_print) {
echo $lines[$i];
}
An efficient solution is
$i = 0;
$lines_to_print = [1,3,5,8];
$file = fopen("file.txt", "r");
while(!feof($file)){
$line = fgets($file);
if(in_array(++$i, $lines_to_print)) {
echo $line
}
}
fclose($file);

Categories