`I have a function called lets say calculate; what i want to do is run some loops with in the function calculating an outcome. at times this function does fail as it will get stuck in a loop, so iv got it covered to exit the loop but my problem is i want to restart this function and hope it come out with an outcome if not i will try again... on average the request does not have an outcome around 1 in 20, i need to restart the function from a clean slate.
i have tried to unset all the vars before i rerun the process with out success.please note this function will fail at times from the information handed to the process, un avoidable so
when this accurs i just want to rerun the function automatically to generate an outcome.
http://www.gamezslave.com/test/DynamicSlots.swf this is my test prototype give you an idea
sometimes you refresh it will error because of this factor.
<?php
$checker = 0; // if i cant get a result i could use this will tick up until condition
function shuffleArray($myArray) {
$value_count = array_count_values($myArray);
$last_value = $myArray[count($myArray) - 1];
unset($myArray[count($myArray) - 1]);
$shuffle = array();
$last = false;
while (count($myArray) > 0) {
$keys = array_keys($myArray);
$i = round(rand(0, count($keys) - 1));
while ($last === $myArray[$keys[$i]] ) {
$i = round(rand(0, count($keys) - 1));
echo "stuck";
$checker++;
if($checker>10){
echo " Too many checks so die, and restart process ";
return false;
bob; // this is the check function to goto and restart
}
}
$shuffle[] = $myArray[$keys[$i]];
$last = $myArray[$keys[$i]];
unset($myArray[$keys[$i]]);
}
if ($last_value === $last) {
$i = 0;
foreach($shuffle as $key=>$value) {
if ($value !== $last_value) {
$i = $key;
break;
}
}
array_slice($shuffle, $i + 1, 0, $last_value);
} else {
$shuffle[] = $last_value;
}
return $shuffle;
}
print_r(shuffleArray(array(1,5,5,3,7,7,7,7))); // just a example
function bob(){
if($checker>10){
$checker = 0;
shuffleArray();
echo "bob";
reset($myArray); // thought this may clean/reset the array i couldnt use
}
}
The idea this shuffle returns that no two symbols elemts of the same will be next to each other but sometimes at the end of the array as its shuffling randomly im left with bad odds (apple, orange, orange, orange) so what i need to do is resart this process again from start take in mind there is about 10 different item in the array and duplicates of each for example 10 apples ,10 oranges 4 bannanas 3 grapes sometimes the shuffle manages to generate an outcome where im stuck with too many of the same item at the end of the array wich then i need to rerun the script(and this bit is the problem) i dont know how.
Are you using globals?
If yes: Stop that. It's terrible practice. Seriously. There's never a reason to use globals with any sort of sane code.
If no: There's nothing to do. Each function invocation is a clean slate.
EDIT After seeing the code, I'm kinda speechless.
http://us3.php.net/manual/en/function.shuffle.php
I would set defaults to all variables inside of your function, and pass anything active as a parameter. Then use a set of return codes to indicate success or failure, or validate the outcome in some way and re-run.
I'm agreeing with Tyler Eaves here and i wanted to add as another reply a very important topic in programming:
A function "should" in theory be as scalar as possible meaning that it should not affect the outside world and should return the same information everytime for the same parameters.
If you call a function with parameter X, Y and Z and call it again while your system is in the same state, the function should return the exact same result.
But if a function is not scalar (Virtual for instance), such as dependant on external data (files, database rows or single instance accessible class data) then you should theorically not affect that external data from this function or else calling the function multiple times yield different results...
Related
I need a program in PHP, when I search a number in a given series like 1,3,7,15,31... and if it is present in the series then give output as the index on which it is present in series?
LIKE I HAVE DONE SOMETHING TO DO THIS BUT FAILED.
<?php
function test1($n) {
for($i=1;$i<=$n;$i=$c) {
$c =1 + (2 * $i);
}
}
function test2($p) {
global $c,$n;
$input=array(1);
$in=array_push($input,$c);
$k=array_search($p,$input);
$flipped = array_flip($k);
var_dump($flipped);
}
test1(1000000);
test2(45);
Like in this program I had made two functions and in FUNCTION test1 I made a formula to make the series 1,3,7,15,31,63,127.... and in FUNCTION test2 I insert a number in form of parameter and want to SEARCH that number in the series that I form above and the I want OUTPUT as the index of that number searched.
Also if the number is not present in the series then I want the output as the nearest number of the number I search.
HELP.!!!
Thank You
You've got a few problems with this code.
function test1($n) {
for($i=1;$i<=$n;$i=$c) {
$c =1 + (2 * $i);
}
}
The first problem here is that you don't do anything with $c each time you increment it. You should probably be pushing it into an array of series integers.
Secondly you don't return a result, so you can't actually use the series you would've created.
You could use something like this instead:
function test1($limit) {
$series = [];
for ($i = 1; $i <= $limit; $i = $i * 2 + 1) {
$series[] = $i;
}
return $series;
}
Next, your test2 function:
function test2($p) {
global $c,$n;
$input=array(1);
$in=array_push($input,$c);
$k=array_search($p,$input);
$flipped = array_flip($k);
var_dump($flipped);
}
Ok, first don't use global variables. Pass the ones you need in as arguments and again, return the result. To be perfectly honest, I'm not entirely sure what this function is supposed to do. All you need is the array_search call which "searches the array for a given value and returns the first corresponding key if successful".
For example:
function test2($series, $number) {
return array_search($number, $series);
}
Using these, you can do something like this:
$series = test1(1000000);
var_dump(test2($series, 45)); // bool(false)
var_dump(test2($series, 31)); // int(4)
Also if the number is not present in the series then I want the output as the nearest number of the number I search.
Ok, you'll need to write some custom logic for this. I suggest you run your array_search check, then if it returns false you loop through your series and check the following criteria:
The previous series entry is lower than your number
The next series entry is higher than your number
Then return whichever of those two has a smaller absolute difference when you subtract the series entry from your number.
I'm not going to write an example for this because it smells a bit like a school assignment, which I'm sure you're capable of doing =) good luck.
I'm getting stuck with maybe a simple question. I created a new class with many calculations inside. I have a recursive array to dynamically generate SQL from a Die result. When the result is between a given range, I'll have to do an extra operation.
I've got this multi-dimensional array to fill with the value of my dice, using an array of IDs as my first "key":
$this->multidim[$id_object][]
I was thinking about creating another function to populate it, but I'm unsure how to build it correctly. The specifications of this function I need are the following:
I need to call a function with the multidimensional array, and
If the result is 100, I need to re-roll the dice twice, and check the result again
$this->checkresult($id_obj, $die);
function checkresult($id_obj, $die)
{
if ($die == 100){
$rand1 = $this->launchDie(1, 100);
$rand2 = $this->launchDie(1, 100);
if($this->checkresult($array, $rand1)) {
if($this->checkresult($array, $rand2)) {
return 1;
}
}
} else {
if (!isset($array[$tiro])) {
$this->multidim[$id_obj][$die] = 1;
}
return 1;
}
}
Is this approach correct? I feel uncomfortable not returning a "real" value, but as I said I need to re-call that function recursively.
You can return the rolled value like this:
public function addResult($object_id, $result)
{
$this->multidim[$object_id][] = $result;
}
public function checkResult($object_id)
{
$roll = $this->launchDie(1, 100);
if ($roll == 100) {
$additionalRoll = $this->checkResult($object_id);
$this->addResult($object_id, $additionalRoll);
$roll = $this->checkResult();
}
return $roll;
}
And call it like this:
$this->addResult($object_id, $this->checkResult($object_id));
This way each time a 100 is rolled there will be two rolls instead of the one. Please note that this could go on forever (improbable, though ;)).
Also note that I changed the structure of your multidim array, as it made more sense to me that way, you may need to change that back if it doesn't match what you would like to achieve.
For ex. If I have a function rand(0,2). How do i build a function such that
resc(100,rand(0,2));
Prints the value of rand(0,2) 100 times? For that matter. Any function that is printable.
I tried this.But doesnt seem to work.
<?php
function resc($i, $f) {
if ($i != 0) {
print $f;
return resc($i-1, $f);
} else {
print $f;
}
}
resc(4, rand(0, 1));
?>
If you just want to print a bunch of random ints:
function resc_int($recursions, callable $func, $args = array()) {
for($i = 0; $i < $recursions; $i++) {
echo call_user_func_array($func, $args);
}
}
// resc_int(100, "rand", array(0, 1));
Completely untested. Caveat Lector.
The way this works is that instead of using recursion (which will use more and more memory the more recursions you have, as you can't garbage collect something with active references or you will get a segmentation fault later in PHP if it tries to access it), it uses iteration.
There's two kinds of "looping" in a sense.
Looping/Recursion.
Technically Recursion is a loop, as you continue recursing until you reach a stop condition (else you get an infinite loop, which is bad for fairly painful reasons). The loop construct in PHP is while().
Iteration
In pretty much every single case (unless you have a really good reason) this is always the better choice when you need something that loops. Iteration is, to put it simply, counting up or down to a target integer. This is the for() construct; and hence, also the foreach() construct, which uses the number of elements in an array as a target integer and then counts towards it, picking elements out of the array as it goes.
This is more memory efficient, and is remarkably easy to work with in PHP. It can also infinite loop, like while can (just give it an impossible condition to work towards), so watch out for that.
In short: have fun with the standard library (pretty much every function you regularly need is somewhere in there), and remember that recursion is your last option, not the first.
function resc($times, $cbFtn, Array $cbFtnArgs = array()) {
if ($times != 0) {
print call_user_func_array($cbFtn, $cbFtnArgs);
resc($times - 1, $cbFtn, $cbFtnArgs);
}
}
resc(4, 'rand', array(0, 1));
I've recently stumbled over this code:
function xrange($min, $max)
{
for ($i = $min; $i <= $max; $i++) {
yield $i;
}
}
I've never seen this yield keyword before. Trying to run the code I get
Parse error: syntax error, unexpected T_VARIABLE on line x
So what is this yield keyword? Is it even valid PHP? And if it is, how do I use it?
What is yield?
The yield keyword returns data from a generator function:
The heart of a generator function is the yield keyword. In its simplest form, a yield statement looks much like a return statement, except that instead of stopping execution of the function and returning, yield instead provides a value to the code looping over the generator and pauses execution of the generator function.
What is a generator function?
A generator function is effectively a more compact and efficient way to write an Iterator. It allows you to define a function (your xrange) that will calculate and return values while you are looping over it:
function xrange($min, $max) {
for ($i = $min; $i <= $max; $i++) {
yield $i;
}
}
[…]
foreach (xrange(1, 10) as $key => $value) {
echo "$key => $value", PHP_EOL;
}
This would create the following output:
0 => 1
1 => 2
…
9 => 10
You can also control the $key in the foreach by using
yield $someKey => $someValue;
In the generator function, $someKey is whatever you want appear for $key and $someValue being the value in $val. In the question's example that's $i.
What's the difference to normal functions?
Now you might wonder why we are not simply using PHP's native range function to achieve that output. And right you are. The output would be the same. The difference is how we got there.
When we use range PHP, will execute it, create the entire array of numbers in memory and return that entire array to the foreach loop which will then go over it and output the values. In other words, the foreach will operate on the array itself. The range function and the foreach only "talk" once. Think of it like getting a package in the mail. The delivery guy will hand you the package and leave. And then you unwrap the entire package, taking out whatever is in there.
When we use the generator function, PHP will step into the function and execute it until it either meets the end or a yield keyword. When it meets a yield, it will then return whatever is the value at that time to the outer loop. Then it goes back into the generator function and continues from where it yielded. Since your xrange holds a for loop, it will execute and yield until $max was reached. Think of it like the foreach and the generator playing ping pong.
Why do I need that?
Obviously, generators can be used to work around memory limits. Depending on your environment, doing a range(1, 1000000) will fatal your script whereas the same with a generator will just work fine. Or as Wikipedia puts it:
Because generators compute their yielded values only on demand, they are useful for representing sequences that would be expensive or impossible to compute at once. These include e.g. infinite sequences and live data streams.
Generators are also supposed to be pretty fast. But keep in mind that when we are talking about fast, we are usually talking in very small numbers. So before you now run off and change all your code to use generators, do a benchmark to see where it makes sense.
Another Use Case for Generators is asynchronous coroutines. The yield keyword does not only return values but it also accepts them. For details on this, see the two excellent blog posts linked below.
Since when can I use yield?
Generators have been introduced in PHP 5.5. Trying to use yield before that version will result in various parse errors, depending on the code that follows the keyword. So if you get a parse error from that code, update your PHP.
Sources and further reading:
Official docs
The original RFC
kelunik's blog: An introduction to generators
ircmaxell's blog: What generators can do for you
NikiC's blog: Cooperative multitasking using coroutines in PHP
Co-operative PHP Multitasking
What is the difference between a generator and an array?
Wikipedia on Generators in general
This function is using yield:
function a($items) {
foreach ($items as $item) {
yield $item + 1;
}
}
It is almost the same as this one without:
function b($items) {
$result = [];
foreach ($items as $item) {
$result[] = $item + 1;
}
return $result;
}
The only one difference is that a() returns a generator and b() just a simple array. You can iterate on both.
Also, the first one does not allocate a full array and is therefore less memory-demanding.
simple example
<?php
echo '#start main# ';
function a(){
echo '{start[';
for($i=1; $i<=9; $i++)
yield $i;
echo ']end} ';
}
foreach(a() as $v)
echo $v.',';
echo '#end main#';
?>
output
#start main# {start[1,2,3,4,5,6,7,8,9,]end} #end main#
advanced example
<?php
echo '#start main# ';
function a(){
echo '{start[';
for($i=1; $i<=9; $i++)
yield $i;
echo ']end} ';
}
foreach(a() as $k => $v){
if($k === 5)
break;
echo $k.'=>'.$v.',';
}
echo '#end main#';
?>
output
#start main# {start[0=>1,1=>2,2=>3,3=>4,4=>5,#end main#
yield keyword serves for definition of "generators" in PHP 5.5.
Ok, then what is a generator?
From php.net:
Generators provide an easy way to implement simple iterators without the overhead or complexity of implementing a class that implements the Iterator interface.
A generator allows you to write code that uses foreach to iterate over a set of data without needing to build an array in memory, which may cause you to exceed a memory limit, or require a considerable amount of processing time to generate. Instead, you can write a generator function, which is the same as a normal function, except that instead of returning once, a generator can yield as many times as it needs to in order to provide the values to be iterated over.
From this place: generators = generators, other functions (just a simple functions) = functions.
So, they are useful when:
you need to do things simple (or simple things);
generator is really much simplier then implementing the Iterator interface. other hand is, ofcource, that generators are less functional. compare them.
you need to generate BIG amounts of data - saving memory;
actually to save memory we can just generate needed data via functions for every loop iteration, and after iteration utilize garbage. so here main points is - clear code and probably performance. see what is better for your needs.
you need to generate sequence, which depends on intermediate values;
this is extending of the previous thought. generators can make things easier in comparison with functions. check Fibonacci example, and try to make sequence without generator. Also generators can work faster is this case, at least because of storing intermediate values in local variables;
you need to improve performance.
they can work faster then functions in some cases (see previous benefit);
None of the answers show a concrete example using massive arrays populated by non-numeric members. Here is an example using an array generated by explode() on a large .txt file (262MB in my use case):
<?php
ini_set('memory_limit','1000M');
echo "Starting memory usage: " . memory_get_usage() . "<br>";
$path = './file.txt';
$content = file_get_contents($path);
foreach(explode("\n", $content) as $ex) {
$ex = trim($ex);
}
echo "Final memory usage: " . memory_get_usage();
The output was:
Starting memory usage: 415160
Final memory usage: 270948256
Now compare that to a similar script, using the yield keyword:
<?php
ini_set('memory_limit','1000M');
echo "Starting memory usage: " . memory_get_usage() . "<br>";
function x() {
$path = './file.txt';
$content = file_get_contents($path);
foreach(explode("\n", $content) as $x) {
yield $x;
}
}
foreach(x() as $ex) {
$ex = trim($ex);
}
echo "Final memory usage: " . memory_get_usage();
The output for this script was:
Starting memory usage: 415152
Final memory usage: 415616
Clearly memory usage savings were considerable (ΔMemoryUsage -----> ~270.5 MB in first example, ~450B in second example).
With yield you can easily describe the breakpoints between multiple tasks in a single function. That's all, there is nothing special about it.
$closure = function ($injected1, $injected2, ...){
$returned = array();
//task1 on $injected1
$returned[] = $returned1;
//I need a breakpoint here!!!!!!!!!!!!!!!!!!!!!!!!!
//task2 on $injected2
$returned[] = $returned2;
//...
return $returned;
};
$returned = $closure($injected1, $injected2, ...);
If task1 and task2 are highly related, but you need a breakpoint between them to do something else:
free memory between processing database rows
run other tasks which provide dependency to the next task, but which are unrelated by understanding the current code
doing async calls and wait for the results
and so on ...
then generators are the best solution, because you don't have to split up your code into many closures or mix it with other code, or use callbacks, etc... You just use yield to add a breakpoint, and you can continue from that breakpoint if you are ready.
Add breakpoint without generators:
$closure1 = function ($injected1){
//task1 on $injected1
return $returned1;
};
$closure2 = function ($injected2){
//task2 on $injected2
return $returned1;
};
//...
$returned1 = $closure1($injected1);
//breakpoint between task1 and task2
$returned2 = $closure2($injected2);
//...
Add breakpoint with generators
$closure = function (){
$injected1 = yield;
//task1 on $injected1
$injected2 = (yield($returned1));
//task2 on $injected2
$injected3 = (yield($returned2));
//...
yield($returnedN);
};
$generator = $closure();
$returned1 = $generator->send($injected1);
//breakpoint between task1 and task2
$returned2 = $generator->send($injected2);
//...
$returnedN = $generator->send($injectedN);
note: It is easy to make mistake with generators, so always write unit tests before you implement them!
note2: Using generators in an infinite loop is like writing a closure which has infinite length...
An interesting aspect, which worth to be discussed here, is yielding by reference. Every time we need to change a parameter such that it is reflected outside of the function, we have to pass this parameter by reference. To apply this to generators, we simply prepend an ampersand & to the name of the generator and to the variable used in the iteration:
<?php
/**
* Yields by reference.
* #param int $from
*/
function &counter($from) {
while ($from > 0) {
yield $from;
}
}
foreach (counter(100) as &$value) {
$value--;
echo $value . '...';
}
// Output: 99...98...97...96...95...
The above example shows how changing the iterated values within the foreach loop changes the $from variable within the generator. This is because $from is yielded by reference due to the ampersand before the generator name. Because of that, the $value variable within the foreach loop is a reference to the $from variable within the generator function.
The below code illustrates how using a generator returns a result before completion, unlike the traditional non generator approach that returns a complete array after full iteration. With the generator below, the values are returned when ready, no need to wait for an array to be completely filled:
<?php
function sleepiterate($length) {
for ($i=0; $i < $length; $i++) {
sleep(2);
yield $i;
}
}
foreach (sleepiterate(5) as $i) {
echo $i, PHP_EOL;
}
When implement PHP IteratorAggregate interface, the yield keyword will be useful. Check out the documentation, there are couple examples either using ArrayIterator or yield.
Another example can be found is in the php-ds/polyfill repo: https://github.com/php-ds/polyfill/blob/e52796c50aac6e6cfa6a0e8182943027bacbe187/src/Traits/GenericSequence.php#L359
The idea is similar to the quick example below:
class Collection implements \IteratorAggregate
{
private $array = [];
public function push(...$values)
{
array_push($this->array, ...$values);
}
public function getIterator()
{
foreach ($this->array as $value) {
yield $value;
}
}
}
$collection = new Collection();
$collection->push('apple', 'orange', 'banana');
foreach ($collection as $key => $value) {
echo sprintf("[%s] => %s\n", $key, $value);
}
Output:
[0] => apple
[1] => orange
[2] => banana
I have this function that I wrote that is abysmally slow since php does not handle recursion well. I am trying to convert it to a while loop, but am having trouble wrapping my head around how to do it.
Can anyone give me some tips?
public function findRoute($curLoc, $distanceSoFar, $expectedValue) {
$this->locationsVisited[$curLoc] = true;
$expectedValue += $this->locationsArray[$curLoc]*$distanceSoFar;
$at_end = true;
for($i = 1; $i < $this->numLocations; $i++) {
if($this->locationsVisited[$i] == false) {
$at_end = false;
if($expectedValue < $this->bestEV)
$this->findRoute($i, $distanceSoFar + $this->distanceArray[$curLoc][$i], $expectedValue);
}
}
$this->locationsVisited[$curLoc] = false;
if($at_end) {
if($expectedValue < $this->bestEV) {
$this->bestEV = $expectedValue;
}
}
}
I'm not going to convert your code, but you can convert a recusive function into an iterative one by creating a stack:
$stack= array();
And instead of invoking $this->findroute(), push your parameters onto this stack:
$stack[] = array($i, $distanceSoFar + $this->distanceArray[$curLoc][$i], $expectedValue);
Now surround basically everything in your function into a while loop draining the stack after having primed it:
while ($stack) {
// Do stuff you already do in your function here
You can convert a recursive function into an iterative function by using a stack to store the current state. Look into array_push() and array_pop().
At a glance I don't think recursion is your problem, yes it's slow in PHP, but It looks like your going over values more than you need to, putting the values in a stack, or several stacks and handling them, may be nice.
custom sort functions have always helped me with problems of this sort.
function sort_by_visited($x,$y)
{
return ($this->locationsVisited[$x] > $this->locationsVisited[$y]) ? -1 : 1;
}
uasort($locationsVisited,'sort_by_visited');
This will prioritize all not visited locations at the top of the stack.
This looks like your trying to find the optimal route for traversal of a series of nodes in a graph.
I'm guessing that you've not studied Computer Science as the "Travelling Salesman" problem is an archetype of Artificial Intelligence. Of course, as such, it has its own Wikipedia page:
http://en.wikipedia.org/wiki/Travelling_salesman_problem
Sorry - but just swapping from a recursive to an iterative function isn't going to make it go any faster ("php does not handle recursion well." - can you provide reference for this assertion). If you need a faster solution then you'll need to look at non-exhaustive/fuzzy methods.
C.