I have around 900 combinations which need to check through an external party for validation.I need to perform below-mentioned steps :
Step 1 : Insert all 900 combinations in table [DONE]
Now I need to do this
Step 2: Run a call every few secs (add PHP wait function)
Step 3: store the result in the DB
so that if something fails, we can start it again from where it failed
Tried php code :
$t0 = microtime(true);
$i = 0;
do{
$dt = round(microtime(true)-$t0);
if($dt!= $i){
$i = $dt;
if(($i % 2) == 0) //every 2 seconds
echo $i.PHP_EOL;
}
}
while($dt<10); //max execution time
Cannot use setInterval in javascript.
I usually use sleep(2). In case you want more granular you can use time_nanosleep
Please also find an example how to make chunks in php.
$arr = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
$chunked = array_chunk($arr, 5);
$res = [];
$flag = 0;
foreach($chunked as $arr){
sleep(2);
echo 'sleep';
foreach ($arr as $val) {
var_dump($val);
}
}
Related
Im trying to slice an array on 30 at a time to send a call to an endpoint which can only recibe 30 codes at a time. Right now I have about 203 lines in the array. Everything is fine until the 4th round where I don't know why the indexes (init and endt) I've set up, get messed up and the slice no longer works which in turns makes the call to the endpoint impossible. Here is the code:
$arrcount = ceil(count($requestarr['SelectionDetails'])/30);
$init = 0;
if (count($requestarr['SelectionDetails']) > 30) {
$endt = 29;
} else {
$endt = count($requestarr['SelectionDetails']);
}
for ($i=0; $i < $arrcount; $i++) {
$request['SelectionDetails'] = array_slice($requestarr['SelectionDetails'], $init, $endt);
$init = $endt+1;
if (count($requestarr['SelectionDetails']) > ($endt+30)) {
$endt += 30;
} else {
$endt = count($requestarr['SelectionDetails']);
}
//call to endpoind and other code here....
}
The requestarr[] has the whole 203 indexes and the request[] contains the 30 indexes slice sent each loop. Its worth noticing that my array has "custom" keys that are tracking numbers from FedEx. At the 4th loop, the init turns into 120 and the endt turns into 113. Im not sure how or why this happens. Needless to say the next 3 for loops the endt gets reduced by 7 then by 34 and finally by 1. There is no code where the endt should be decreasing. So I'm not sure how this is happening. Any ideas? If you need more information or more code I'll gladly help.
To split items into chunks - use array_chunk:
$chunks = array_chunk($your_data, 30);
foreach ($chunks as $chunk) {
// send $chunk to endpoint
}
$arrcount = ceil(count($requestarr['SelectionDetails'])/30);
for ($i=0; $i < $arrcount; $i++) {
$request['SelectionDetails'] = array_slice($requestarr['SelectionDetails'], $i * 30, 30);
//call to endpoind and other code here....
}
array_slice can take a length argument longer than the array. You just have to move the starting point.
echo "counter: ";
$i=1;
while ($i <= 5) {
print($i);
sleep(1);
$i++;
}
The above will output: counter: 12345 I need to output eg.: loop 3 - counter: 3 (one digit per loop)
How to do it:
1) When running in a browser?
2) When running from command line (php index.php)?
I think you want to make an auto-updated string. It's impossible to make it with only PHP. You should use Javascript (or a library like jQuery) and send the data from PHP via Ajax call.
You can even do this only with Javascript.
var counter = 1;
setInterval(function () {
counter++;
}, 5);
For command line you can use your code with "\r" at the end of the string.
$i=0;
while ($i <= 5) {
sleep(1);
$i++;
echo "counter: $i\r";
}
I think this is what you need. The counter string was brought inside the loop and a break was added for a new line simulation. Also the < was changed to <= as the loop was running for 4 times instead of 1.
$i=1;
while ($i <= 5) {
print("counter: $i <br>");
sleep(1);
$i++;
}
Suppose I have many(thousand) rows, now I want to divide data it in 3 columns so what is better option 1) using single for loop 2) divide array in 3 chunks and then use for loop for each chunk . Whose speed will be fast?
I would use a single for loop.
But the algorithm depends on a few factors. Do we know how many rows you have?
That way you can just divide by 3. And after the loop reaches a 3rd done, create new chunk.
User single array and **foreach** to traverse the array, foreach is better one.
foreach keep the inner pointer move forward one element each step.
or you can use each to traverse an array.
each — Return the current key and value pair from an array and advance
the array cursor
while (list ($key, $val) = each ($para)) {
echo $key."=".$val;
}
Here is an performance test from the manual example and the result:
Regarding speed of foreach vs while(list) =each I wrote a benchmark
script and the results are that clearly foreach is faster. MUCH
faster. Even with huge arrays (especially with huge arrays). I tested
with sizes 100,000. 1,000,000 and 10,000,000. To do the test with 10
million i had to set my memory limit real high, it was close to 1gb by
the time it actually worked. Anyways,
> <?php function getDiff($start, $end) {
> $s = explode(' ', $start);
> $stot = $s[1] + $s[0];
> $e = explode(' ', $end);
> $etot = $e[1] + $e[0];
> return $etot - $stot; }
>
> $lim=10000000; $arr = array(); for ($i=0; $i<$lim; $i++) {
> $arr[$i] = $i/2; }
>
> $start = microtime(); foreach ($arr as $key=>$val);
>
> $end = microtime(); echo "time for foreach = " . getDiff($start, $end)
> . ".\n";
>
> reset($arr); $start = microtime(); while (list($key, $val) =
> each($arr)); $end = microtime(); echo "time list each = " .
> getDiff($start, $end) . ".\n"; ?>
>
> here are some of my results: with 1,000,000 time for foreach =
> 0.0244591236115. time list each = 0.158002853394. desktop:/media/sda5/mpwolfe/tests$ php test.php time for foreach =
> 0.0245339870453. time list each = 0.154260158539. desktop:/media/sda5/mpwolfe/tests$ php test.php time for foreach =
> 0.0269000530243. time list each = 0.157305955887.
>
> then with 10,000,000: desktop:/media/sda5/mpwolfe/tests$ php test.php
> time for foreach = 1.96586894989. time list each = 14.1371650696.
> desktop:/media/sda5/mpwolfe/tests$ php test.php time for foreach =
> 2.02504014969. time list each = 13.7696218491. desktop:/media/sda5/mpwolfe/tests$ php test.php time for foreach =
> 2.0246758461. time list each = 13.8425710201.
>
> by the way, these results are with php 5.2 i believe, and a linux
> machine with 3gb of ram and 2.8ghz dual core pentium
as commented by Franz Gleichmann in my case this was right answer "unless you use multiple threads, it does not matter greatly. because if you have 12345 rows, you will have to process 12345 rows. chunking it up will only help if you parallelize the workload."
I have such an array of intervals sorted by the lower bound ($a[$i] <= $a[$i+1] for every $i), key l is lower bound and , key h is upper bound and I'd like to remove all rows with intervals that are enclosed by larger intervals.
$a[0] = array('l' => 123, 'h'=>241);
$a[1] = array('l' => 250, 'h'=>360);
$a[2] = array('l' => 280, 'h'=>285);
$a[3] = array('l' => 310, 'h'=>310);
$a[4] = array('l' => 390, 'h'=>400);
So the result I'd like to get is
$a[0] = array('l' => 123, 'h'=>241);
$a[1] = array('l' => 250, 'h'=>360);
$a[2] = array('l' => 390, 'h'=>400);
This is what I attempted
function dup($a){
$c = count($a)-1;
for ($i = $c; $i > 0; $i --){
while ($a[$i]['h'] <= $a[$i-1]['h']){
unset($a[$i]);
}
}
$a = array_values($a);
}
The first answer which comes in mind was given with different variations by other contributors : for each interval, loop on each interval looking for a larger and enclosing interval. It's simple to understand and to write, and it works for sure.
This is basically n2 order, which means for n intervals we'll do n*n loop turns. There can be some tricks to optimize it :
break'ing when we find an enclosing interval in the nested loop, as in user3137702's answer, because it's useless to continue if we find at least one enclosing interval
avoiding looping on the same interval in the nested loop because we know an interval cant be strictly enclosed in itself (not significant)
avoiding looping on already excluded intervals in the nested loop (can have a significant impact)
looping on intervals (global loop) in ascending width = (h - l) order, because smaller intervals have more chance to be enclosed in others and the earliest we eliminate intervals, the more the next loop turns are effective (can be significant too in my opinion)
searching for enclosing intervals (nested loop) in descending width order, because larger intervals have more chance to be enclosing other intervals (I think it can have a significant impact too)
probably many other things that do not come to mind at the moment
Let me say now that :
optimization does not matter much if we have only few intervals to compute from time to time, and currently accepted user3137702's answer does the trick
to develop the suitable algorithm, it is necessary anyway to study the characteristics of the data that we have to deal with : in the case before us, how is the distribution of intervals ? Are there many enclosed intervals ? This can help to choose from the above list, the most useful tricks.
For educational purposes, I wondered if we could develop a different algorithm avoiding a n*n order which running time is necessarily very quickly deteriorated gradually as you increase the number of intervals to compute.
"Virtual rule" algorithm
I imagined this algorithm I called the "virtual rule".
place starting and ending points of the intervals on a virtual rule
run through the points along the rule in ascending order
during the run, register open or not intervals
when an interval starts and ends while another was opened before and is still open, we can say it is enclosed
so when an interval ends, check if it was opened after one of the other currently open intervals and if it is strictly closed before this interval. If yes, it is enclosed !
I do not pretend this is the best solution. But we can assume this is faster than the basic method because, despite many tests to do during the loop, this is n order.
Code example
I wrote comments to make it as clear as possible.
<?php
function removeEnclosedIntervals_VirtualRule($a, $debug = false)
{
$rule = array();
// place one point on a virtual rule for each low or up bound, refering to the interval's index in $a
// virtual rule has 2 levels because there can be more than one point for a value
foreach($a as $i => $interval)
{
$rule[$interval['l']][] = array('l', $i);
$rule[$interval['h']][] = array('h', $i);
}
// used in the foreach loop
$open = array();
$enclosed = array();
// loop through the points on the ordered virtual rule
ksort($rule);
foreach($rule as $points)
{
// Will register open intervals
// When an interval starts and ends while another was opened before and is still open, it is enclosed
// starts
foreach($points as $point)
if($point[0] == 'l')
$open[$point[1]] = $point[1]; // register it as open
// ends
foreach($points as $point)
{
if($point[0] == 'h')
{
unset($open[$point[1]]); // UNregister it as open
// was it opened after a still open interval ?
foreach($open as $i)
{
if($a[$i]['l'] < $a[$point[1]]['l'])
{
// it is enclosed.
// is it *strictly* enclosed ?
if($a[$i]['h'] > $a[$point[1]]['h'])
{
// so this interval is strictly enclosed
$enclosed[$point[1]] = $point[1];
if($debug)
echo debugPhrase(
$point[1], // $iEnclosed
$a[$point[1]]['l'], // $lEnclosed
$a[$point[1]]['h'], // $hEnclosed
$i, // $iLarger
$a[$i]['l'], // $lLarger
$a[$i]['h'] // $hLarger
);
break;
}
}
}
}
}
}
// obviously
foreach($enclosed as $i)
unset($a[$i]);
return $a;
}
?>
Benchmarking against basic method
It runs tests on randomly generated intervals
basic method works without a doubt. Comparing results from the two methods allows me to predent the "VirtualRule" method works because as far as I tested, it returned the same results
// * include removeEnclosingIntervals_VirtualRule function *
// arbitrary range for intervals start and end
// Note that it could be interesting to do benchmarking with different MIN and MAX values !
define('MIN', 0);
define('MAX', 500);
// Benchmarking params
define('TEST_MAX_NUMBER', 100000);
define('TEST_BY_STEPS_OF', 100);
// from http://php.net/manual/en/function.microtime.php
// used later for benchmarking purpose
function microtime_float()
{
list($usec, $sec) = explode(" ", microtime());
return ((float)$usec + (float)$sec);
}
function debugPhrase($iEnclosed, $lEnclosed, $hEnclosed, $iLarger, $lLarger, $hLarger)
{
return '('.$iEnclosed.')['.$lEnclosed.' ; '.$hEnclosed.'] is strictly enclosed at least in ('.$iLarger.')['.$lLarger.' ; '.$hLarger.']'.PHP_EOL;
}
// 2 foreach loops solution (based on user3137702's *damn good* work ;) and currently accepted answer)
function removeEnclosedIntervals_Basic($a, $debug = false)
{
foreach ($a as $i => $valA)
{
$found = false;
foreach ($a as $j => $valB)
{
if (($valA['l'] > $valB['l']) && ($valA['h'] < $valB['h']))
{
$found = true;
if($debug)
echo debugPhrase(
$i, // $iEnclosed
$a[$i]['l'], // $lEnclosed
$a[$i]['h'], // $hEnclosed
$j, // $iLarger
$a[$j]['l'], // $lLarger
$a[$j]['h'] // $hLarger
);
break;
}
}
if (!$found)
{
$out[$i] = $valA;
}
}
return $out;
}
// runs a benchmark with $number intervals
function runTest($number)
{
// Generating a random set of intervals with values between MIN and MAX
$randomSet = array();
for($i=0; $i<$number; $i++)
// avoiding self-closing intervals
$randomSet[] = array(
'l' => ($l = mt_rand(MIN, MAX-2)),
'h' => mt_rand($l+1, MAX)
);
/* running the two methods and comparing results and execution time */
// Basic method
$start = microtime_float();
$Basic_result = removeEnclosedIntervals_Basic($randomSet);
$end = microtime_float();
$Basic_time = $end - $start;
// VirtualRule
$start = microtime_float();
$VirtualRule_result = removeEnclosedIntervals_VirtualRule($randomSet);
$end = microtime_float();
$VirtualRule_time = $end - $start;
// Basic method works for sure.
// If results are the same, comparing execution time. If not, sh*t happened !
if(md5(var_export($VirtualRule_result, true)) == md5(var_export($VirtualRule_result, true)))
echo $number.';'.$Basic_time.';'.$VirtualRule_time.PHP_EOL;
else
{
echo '/;/;/;Work harder, results are not the same ! Cant say anything !'.PHP_EOL;
stop;
}
}
// CSV header
echo 'Number of intervals;Basic method exec time (s);VirtualRule method exec time (s)'.PHP_EOL;
for($n=TEST_BY_STEPS_OF; $n<TEST_MAX_NUMBER; $n+=TEST_BY_STEPS_OF)
{
runTest($n);
flush();
}
Results (for me)
As I thought, clearly different performances are obtained.
I ran the tests on a Core i7 computer with PHP5 and on a (old) AMD Quad Core computer with PHP7. There are clear differences in performance between the two versions on my systems ! which in principle can be explained by the difference in PHP versions because the computer that is running PHP5 is much more powerful...
A simplistic approach, maybe not exactly what you want, but should at least point you in the right direction. I can refine it if needed, just a bit busy and didn't want to leave the question unanswered..
$out = [];
foreach ($a as $valA)
{
$found = false;
foreach ($a as $valB)
{
if (($valA['l'] > $valB['l']) && ($valA['h'] < $valB['h']))
{
$found = true;
break;
}
}
if (!$found)
{
$out[] = $valA;
}
}
This is entirely untested, but should end up with only the unique (large) ranges in $out. Overlaps as I mentioned in my comment are unhandled.
The problem was missing break in the while cycle
function dup($a){
$c = count($a)-1;
for ($i = $c; $i > 0; $i --){
while ($a[$i]['h'] <= $a[$i-1]['h']){
unset($a[$i]);
break; //here
}
}
$a = array_values($a);
}
Here is the code
function sort_by_low($item1,$item2){
if($item1['l'] == $item2['l'])
return 0;
return ($item1['l']>$item2['l'])? -1:1;
}
usort($a,'sort_by_low');
for($i=0; $i<count($a); $i++){
for($j=$i+1; $j<count($a);$j++){
if($a[$i][l]<=$a[$j]['l'] && $a[$i][h]>=$a[$j]['h']){
unset($a[$j]);
}
}
}
$a=array_values($a);
Here is the working code (Tested)
$result = array();
usort($a, function ($item1, $item2) {
if ($item1['l'] == $item2['l']) return 0;
return $item1['l'] < $item2['l'] ? -1 : 1;
});
foreach ($a as $element) {
$exists = false;
foreach ($result as $r) {
if (($r['l'] < $element['l'] && $r['h'] > $element['h'])) {
$exists = true;
break;
}
}
if (!$exists) {
$result[] = $element;
}
}
$result will contain the desired result
I'm a beginner with PHP (and programming in general).
To test what I've learned so far I wrote this code, which prints all the possibile combinations of a set number of dice with a certain number of faces. (you'll find the code at the end).
What I want to do is dynamically change the number of nested for loops according to the $dicenumber variable. Right now it can only process 3 dice, since the code is:
for ($d1=1; $d1 <= $d1value ; $d1++) {
for ($d2=1; $d2 <= $d2value ; $d2++) {
for ($d3=1; $d3 <= $d3value ; $d3++) {
array_push(${sum.($d1+$d2+$d3)}, "$d1"."$d2"."$d3");
}
}
}
But I want to change it so that, for example, if $dicenumber were 2, it would produce something like:
for ($d1=1; $d1 <= $d1value ; $d1++) {
for ($d2=1; $d2 <= $d2value ; $d2++) {
array_push(${sum.($d1+$d2)}, "$d1"."$d2");
}
}
I want the code to process for whatever number $dicenumber may be, without limits. Looking around, it seems like I have to add some kind of recursive code, but I don't know how to do that. Any tips? Also, any feedback on what I did wrong in general, would be extremely helpful! thanks!
<?php
//defines the number and type of dice
$dicenumber = 3;
$dtype = 6;
//defines the maximum value of every die
for ($i=1; $i <=$dicenumber ; $i++) {
${d.$i.value} = $dtype;
}
//defines and array for each possible sum resulting from the roll of the given number of dice.
for ($i=$dicenumber; $i <= ($dtype*$dicenumber) ; $i++) {
${sum.$i} = array();
}
//the troublesome piece of code I want to change
for ($d1=1; $d1 <= $d1value ; $d1++) {
for ($d2=1; $d2 <= $d2value ; $d2++) {
for ($d3=1; $d3 <= $d3value ; $d3++) {
array_push(${sum.($d1+$d2+$d3)}, "$d1"."$d2"."$d3");
}
}
}
//prints all the possible roll combinations, each line lists combination that share the same sum
for ($i=$dicenumber; $i <= ($dtype*$dicenumber); $i++) {
print join(" ", ${sum.$i})."<br />";
}
?>
Here we have a two-function process. The first function, buildArrays, creates arrays in the proper format to feed into the second function, allCombinations. So, for this example with 3 d6's in play, buildArrays will produce an array equivalent to this:
$data = array(
array(1, 2, 3, 4, 5, 6),
array(1, 2, 3, 4, 5, 6),
array(1, 2, 3, 4, 5, 6));
I will warn you that as you increase the number of dice and the number of sides, the number of possible combinations increases exponentially! This means that you could place a very large demand on the server, and both timeout and max memory limits will quickly come into play. The arrays generated could be very, very large and quickly consume more than the max memory limit. That said, here we go:
function buildArrays($dicenumber, $dtype){
for ($i = 0; $i<$dicenumber; $i++){
$tmp = array();
for ($j = 1; $j<=$dtype; $j++){
$tmp[] = $j;
}
$data[$i] = $tmp;
}
return $data;
}
function allCombinations($data){
$result = array(array()); //this is crucial, dark magic.
foreach ($data as $key => $array) {
$new_result = array();
foreach ($result as $old_element){
foreach ($array as $element){
if ($key == 0){
$new_result[] = $element;
} else {
$new_result[] = $old_element.$element;
}
}
$result = $new_result;
}
}
return $result;
}
//set variables
$dicenumber = 3;
$dtype = 6;
//set_time_limit(0); //You may need to uncomment this for large values.
//call functions
$data = buildArrays($dicenumber, $dtype);
$results = allCombinations($data);
//print out the results
foreach ($results as $result){
echo $result."<br/>";
}
N.B. This answer is a variant of the cartesian product code
If you have learned functions, you can do a recursive call and keep track of what dicenumber you're on, then increment it each call to the function (and end the loop once you've hit your #).
understanding basic recursion