I need an algorithm that return all possible combination of all characters in one string.
I've tried:
$langd = strlen($input);
for($i = 0;$i < $langd; $i++){
$tempStrang = NULL;
$tempStrang .= substr($input, $i, 1);
for($j = $i+1, $k=0; $k < $langd; $k++, $j++){
if($j > $langd) $j = 0;
$tempStrang .= substr($input, $j, 1);
}
$myarray[] = $tempStrang;
}
But that only returns the same amount combination as the length of the string.
Say the $input = "hey", the result would be: hey, hye, eyh, ehy, yhe, yeh.
You can use a back tracking based approach to systematically generate all the permutations:
// function to generate and print all N! permutations of $str. (N = strlen($str)).
function permute($str,$i,$n) {
if ($i == $n)
print "$str\n";
else {
for ($j = $i; $j < $n; $j++) {
swap($str,$i,$j);
permute($str, $i+1, $n);
swap($str,$i,$j); // backtrack.
}
}
}
// function to swap the char at pos $i and $j of $str.
function swap(&$str,$i,$j) {
$temp = $str[$i];
$str[$i] = $str[$j];
$str[$j] = $temp;
}
$str = "hey";
permute($str,0,strlen($str)); // call the function.
Output:
#php a.php
hey
hye
ehy
eyh
yeh
yhe
My variant (works as well with array or string input)
function permute($arg) {
$array = is_string($arg) ? str_split($arg) : $arg;
if(1 === count($array))
return $array;
$result = array();
foreach($array as $key => $item)
foreach(permute(array_diff_key($array, array($key => $item))) as $p)
$result[] = $item . $p;
return $result;
}
P.S.: Downvoter, please explain your position. This code uses additional str_split and array_diff_key standard functions, but this code snippet is the smallest, it implements pure tail recursion with just one input parameter and it is isomorphic to the input data type.
Maybe it will lose benchmarks a little when comparing with other implementations (but performance is actually almost the same as in #codaddict's answer for several character strings), but why we can't we just consider it as one of the different alternatives which has its own advantages?
I would put all the characters in an array, and write a recursive function that will 'stripe out' all the remaining characters. If the array is empty, to a reference passed array.
<?php
$input = "hey";
function string_getpermutations($prefix, $characters, &$permutations)
{
if (count($characters) == 1)
$permutations[] = $prefix . array_pop($characters);
else
{
for ($i = 0; $i < count($characters); $i++)
{
$tmp = $characters;
unset($tmp[$i]);
string_getpermutations($prefix . $characters[$i], array_values($tmp), $permutations);
}
}
}
$characters = array();
for ($i = 0; $i < strlen($input); $i++)
$characters[] = $input[$i];
$permutations = array();
print_r($characters);
string_getpermutations("", $characters, $permutations);
print_r($permutations);
Prints out:
Array
(
[0] => h
[1] => e
[2] => y
)
Array
(
[0] => hey
[1] => hye
[2] => ehy
[3] => eyh
[4] => yhe
[5] => yeh
)
Ah yes,
combinations = order doens't matter.
permutations = order does matter.
So hey, hye yeh are all the same combination, but 3 separate permutations as mentioned. Watch out that the scale of items goes up very fast. It's called factorial, and is written like 6! = 6*5*4*3*2*1 = 720 items (for a 6 character string). A 10 character string will be 10! = 3628800 permutations already, which is a very big array. In this example it's 3! = 3*2*1 = 6.
My approach uses recursion and no loops, please check and give feedback:
function permute($str,$index=0,$count=0)
{
if($count == strlen($str)-$index)
return;
$str = rotate($str,$index);
if($index==strlen($str)-2)//reached to the end, print it
{
echo $str."<br> ";//or keep it in an array
}
permute($str,$index+1);//rotate its children
permute($str,$index,$count+1);//rotate itself
}
function rotate($str,$index)
{
$tmp = $str[$index];
$i=$index;
for($i=$index+1;$i<strlen($str);$i++)
{
$str[$i-1] = $str[$i];
}
$str[$i-1] = $tmp;
return $str;
}
permute("hey");
I made a simple class that uses Generators to create the permutations.This way you can just iterate over all possible combinations without exhausting the memory.
The class can take either a string or an array,
and returns a Generator object which can be iterated over with foreach.
Obviously the longer the string or array, the longer it takes to generate all the permutations.
This has been build against PHP 7.4
class Permutation {
/** #var string|array **/
protected $permutationRoot;
protected int $permutationLength;
/**
* #param $permutationRoot
*/
protected function __construct( $permutationRoot ) {
$this->permutationRoot = $permutationRoot;
$this->permutationLength = is_array($permutationRoot)
? count($permutationRoot)
: strlen($permutationRoot);
}
/**
* #param string|array $permutationRoot
*
* #return \Generator
*/
public static function resolve( $permutationRoot ): \Generator
{
$instance = new static($permutationRoot);
return $instance->backTrack(
$instance->permutationRoot,
0,
$instance->permutationLength,
);
}
/**
* #param string|array $permutation
* #param int $index
* #param int $length
*
* #return \Generator
*/
protected function backTrack($permutation, int $index, int $length): \Generator
{
if ($index === $length) {
yield $permutation;
}
for ($i = $index; $i < $length; $i++) {
$this->swap($permutation, $index, $i);
yield from $this->backTrack($permutation, $index + 1, $length);
$this->swap($permutation, $index, $i); // backtrack.
}
}
/**
* #param $permutation
* #param int $index
* #param int $n
*
* #return void
*/
protected function swap(&$permutation, int $index, int $n): void {
$temp = $permutation[$index];
$permutation[$index] = $permutation[$n];
$permutation[$n] = $temp;
}
}
// Test
foreach ( Permutation::resolve('hey') as $perm ) {
echo $perm . "\n";
}
$sentence = "This is a cat";
$words = explode(" ", $sentence);
$num_words = count($words);
$uniqueWords = [];
for ($i = 0; $i < $num_words; $i++) {
for ($j = $i; $j < $num_words; $j++) {
$uniqueWord = '';
for ($k = $i; $k <= $j; $k++) {
$uniqueWord .= $words[$k] . ' ';
}
$uniqueWords[] = trim($uniqueWord);
}
}
var_dump($uniqueWords);
This worked for me
Related
A PHP 7 compatibility check pointed out two errors in some PHP 5 code that is not compatible with PHP 7.
'clone' is a reserved keyword introduced in PHP version 5.0 and
cannot be invoked as a function (T_CLONE)
How can the following code be fixed so it is compatible with PHP 7?
/**
* Implements {#link aCssMinifierFilter::filter()}.
*
* #param array $tokens Array of objects of type aCssToken
* #return integer Count of added, changed or removed tokens; a return value larger than 0 will rebuild the array
*/
public function apply(array &$tokens)
{
$r = 0;
$transformations = array("-moz-keyframes", "-webkit-keyframes");
for ($i = 0, $l = count($tokens); $i < $l; $i++)
{
if (get_class($tokens[$i]) === "CssAtKeyframesStartToken")
{
for ($ii = $i; $ii < $l; $ii++)
{
if (get_class($tokens[$ii]) === "CssAtKeyframesEndToken")
{
break;
}
}
if (get_class($tokens[$ii]) === "CssAtKeyframesEndToken")
{
$add = array();
$source = array();
for ($iii = $i; $iii <= $ii; $iii++)
{
$source[] = clone($tokens[$iii]);
}
foreach ($transformations as $transformation)
{
$t = array();
foreach ($source as $token)
{
$t[] = clone($token);
}
$t[0]->AtRuleName = $transformation;
$add = array_merge($add, $t);
}
if (isset($this->configuration["RemoveSource"]) && $this->configuration["RemoveSource"] === true)
{
array_splice($tokens, $i, $ii - $i + 1, $add);
}
else
{
array_splice($tokens, $ii + 1, 0, $add);
}
$l = count($tokens);
$i = $ii + count($add);
$r += count($add);
}
}
}
return $r;
}
}
So, it looks like the code is trying to clone an object. But, you have parentheses around the method.
The code should read
$t[] = clone $token;
clone isn't a function per se, it's a function that calls an object's __clone method
I'm using GMP library of php to solve a problem of formulary.
public function gmp_sum($aRessource)
{
// Avec le while
$i = 0;
$nb_ressource = count($aRessource);
while ($i < $nb_ressource)
{
if ($i == 0)
{
$tmp = gmp_init($aRessource[$i]);
}
else
{
$tmp = gmp_add(gmp_init($aRessource[$i]),$tmp);
}
$i++;
}
return $tmp;
}
The variable $aRessource is equal to : array(1,2,4,8);
so my function gmp_sum is returning 15.
I want to create an algorithm who does the reverse operation, the function take the integer 15 and return me an array who contains 1 2 4 8. But I do not know where to start.
Thanks for the help
Solution :
Decompose integer to power of 2 in php
public function gmp_reverse($gmp_sum)
{
$res = array();
$i = 1;
while ($i < 64) // 64 bytes
{
$tmp = $gmp_sum & $i; // check if bytes equal to 1
if ($tmp != 0)
{
array_push($res,$i);
}
$i = $i * 2;
}
return $res;
}
Assuming you want an array which adds up to the sum, you want a reverse of that. This function assumes, you have a perfect input, so for example, 17 will not work.
Try it out.
function reversegen($gmpsum)
{
$stack = array();
$limit = $gmpsum;
$cur = 1;
for($sum = 0; $sum < $limit; )
{
echo $cur. "<br>";
array_push($stack,$cur);
$sum = $sum + $cur;
$cur = 2 * $cur;
}
return($stack);
}
$stack = reversegen(15);
print_r($stack);
15 above is for representative purpose. You can use, 31, 63, 127 etc and it will still work fine.
Following this tutorial I met the Trie data structure. Since recently I've been programming in PHP I tried to solve the lecture's problem with that. I was able to achieve correct answers, but only for smaller inputs (Input #10 is a 2,82 MB file). Obviously, my algorithm is not scaling well. It also exceeds the default 128 MB memory limit of PHP.
My algorithm
There is a root node stored in Trie. Every node has a "children" member. I use the standard PHP array to store the children. A child key represents a character (currently I am creating a new node for every character, a-z lowercase, mapping to 0-25), a child value is a reference to another node.
The "weight" member that every nodes has is there because of the problem.
I would like to optimize my code, (or even rewrite it from stratch using a different approach) so that it can pass the tests for big inputs.
I'm interested in a solution to make this data structure work in PHP with big inputs, if possible.
My code
TrieNode class stores the tree hierarchy.
class TrieNode {
// weight is needed for the given problem
public $weight;
/* TrieNode children,
* e.g. [0 => (TrieNode object1), 2 => (TrieNode object2)]
* where 0 stands for 'a', 1 for 'c'
* and TrieNode objects are references to other TrieNodes.
*/
private $children;
function __construct($weight, $children) {
$this->weight = $weight;
$this->children = $children;
}
/** map lower case english letters to 0-25 */
static function getAsciiValue($char) {
return intval(ord($char)) - intval(ord('a'));
}
function addChild($char, $node) {
if (!isset($this->children)) {
$this->children = [];
}
$this->children[self::getAsciiValue($char)] = $node;
}
function isChild($char) {
return isset($this->children[self::getAsciiValue($char)]);
}
function getChild($char) {
return $this->children[self::getAsciiValue($char)];
}
function isLeaf() {
return empty($this->children);
}
}
Trie class stores the root TrieNode. It can insert and query nodes.
class Trie {
/* root TrieNode stores the first characters */
private $root;
function __construct() {
$this->root = new TrieNode(-1, []);
}
function insert($string, $weight) {
$currentNode = $this->root;
$l = strlen($string);
for ($i = 0; $i < $l; $i++) {
$char = $string[$i];
if(!$currentNode->isChild($char)) {
$n = new TrieNode($weight, null);
$currentNode->addChild($char, $n);
}
$currentNode->weight = max($weight, $currentNode->weight);
$currentNode = $currentNode->getChild($char);
}
}
function getNode($string) {
$currentNode = $this->root;
$l = strlen($string);
for ($i = 0; $i < $l; $i++) {
$char = $string[$i];
if ($currentNode->isLeaf() || !$currentNode->isChild($char)) {
return null;
}
$currentNode = $currentNode->getChild($char);
}
return $currentNode;
}
function getWeight($string) {
$node = $this->getNode($string);
return is_null($node) ? -1 : $node->weight;
}
}
Test code. Parses input and calls the Trie object.
//MAIN / TEST
/*
In case the problem page is down:
e.g.
INPUT
2 1
hackerearth 10
hackerrank 9
hacker
OUTPUT
10
where 2 is the number of inserts, 1 is the number of queries
"string number" is the string to insert and its "weight"
"hacker" is the string to query
10 is maximum the weight of the queried string (hacker -> 10)
*/
$trie = new Trie();
$handle = fopen('test.txt', 'r');
//$handle = STDIN; // <- this is for the online judge
list($n, $q) = fscanf($handle, "%d %d");
for ($i = 0; $i < $n; $i++) { // insert data
list($s, $weight) = fscanf($handle, "%s %d");
$trie->insert($s, $weight);
}
for ($i = 0; $i < $q; $i++) { // query data
$query = trim(strval(fgets($handle)));
echo $trie->getWeight($query) . PHP_EOL;
}
fclose($handle);
Fail
After making some tweaks and modifications, I have been able to get this thing to work for all the test cases except one test case is timing out,
Here is the whole code that will run successfully for all the test cases except the test case 10.
class TrieNode {
// weight is needed for the given problem
public $weight;
/* TrieNode children,
* e.g. [0 => (TrieNode object1), 2 => (TrieNode object2)]
* where 0 stands for 'a', 1 for 'c'
* and TrieNode objects are references to other TrieNodes.
*/
private $children;
function __construct($weight, $children) {
$this->weight = $weight;
$this->children = $children;
}
/** map lower case english letters to 0-25 */
static function getAsciiValue($char) {
return intval(ord($char)) - intval(ord('a'));
}
function addChild($char, $node) {
if (!isset($this->children)) {
$this->children = [];
}
$this->children[self::getAsciiValue($char)] = $node;
}
function isChild($char) {
return isset($this->children[self::getAsciiValue($char)]);
}
function getChild($char) {
return $this->children[self::getAsciiValue($char)];
}
function isLeaf() {
return empty($this->children);
}
}
class Trie {
/* root TrieNode stores the first characters */
private $root;
function __construct() {
$this->root = new TrieNode(-1, []);
}
function insert($string, $weight) {
$currentNode = $this->root;
$l = strlen($string);
for ($i = 0; $i < $l; $i++) {
$char = $string[$i];
if(!$currentNode->isChild($char)) {
$n = new TrieNode($weight, null);
$currentNode->addChild($char, $n);
}
$currentNode->weight = max($weight, $currentNode->weight);
$currentNode = $currentNode->getChild($char);
}
}
function getNode($string) {
$currentNode = $this->root;
if (empty($currentNode) || !isset($currentNode)) {
return null;
}
$l = strlen($string);
for ($i = 0; $i < $l; $i++) {
$char = $string[$i];
if (empty($currentNode) || $currentNode->isLeaf() || !$currentNode->isChild($char)) {
return null;
}
$currentNode = $currentNode->getChild($char);
if (empty($currentNode)) {
return null;
}
}
return $currentNode;
}
function getWeight($string) {
$node = $this->getNode($string);
return is_null($node) ? -1 : $node->weight;
}
}
$trie = new Trie();
//$handle = fopen('test.txt', 'r');
$handle = STDIN; // <- this is for the online judge
list($n, $q) = fscanf($handle, "%d %d");
for ($i = 0; $i < $n; $i++) { // insert data
list($s, $weight) = fscanf($handle, "%s %d");
$trie->insert($s, $weight);
}
for ($i = 0; $i < $q; $i++) { // query data
$query = trim(strval(fgets($handle)));
echo $trie->getWeight($query) . PHP_EOL;
}
fclose($handle);
I will try to add some more checks so that I could reduce the computation cycles taken by this program.
Below is the code with following optimizations -
Removed all unnecessary condition checks like
No need to check is node is a leaf because if node does not have a child a specified char then it does not matter if it is a leaf or not.
No need to check if {children} is initialized every time you add a child node. Removed this check initialized {children} to empty array in constructor itself.
Removed function to {getAsciiValue} instead using a simple associative array as. Also changing a {char} to ascii value has been moved from TrieNode to Trie class so that we don't need to convert it multiple times
After these optimization i came up following minimal solution, but this also can not pass the test #10. After reading about array in PHP I got to know that PHP does not implement array like other compiled languages, instead any array in PHP is just an ordered hash map and because of this array does not support constant time operations. https://stackoverflow.com/a/4904071/8203131
Also using SplFixedArray but did not help because it is an object and has cost of instantiation. It could have helped if tried using a large array to store whole Trie. You can try implementing a solution to using SplFixedArray to store whole Trie and check if you can get it to pass test #10.
<?php
/*
* Read input from stdin and provide input before running code
fscanf(STDIN, "%s\n", $name);
echo "Hi, ".$name;
*/
class TrieNode {
// weight is needed for the given problem
public $weight;
/* TrieNode children,
* e.g. [0 => (TrieNode object1), 2 => (TrieNode object2)]
* where 0 stands for 'a', 2 for 'c'
* and TrieNode objects are references to other TrieNodes.
*/
private $children;
function __construct($weight) {
$this->weight = $weight;
$this->children = [];
}
function addChild($char, $node) {
$this->children[$char] = $node;
}
function isChild($char) {
return isset($this->children[$char]);
}
function getChild($char) {
return $this->children[$char];
}
}
class Trie {
/* root TrieNode stores the first characters */
private $root;
function __construct() {
$this->root = new TrieNode(-1);
}
static $asciiValues = array(
"a" => 0,
"b" => 1,
"c" => 2,
"d" => 3,
"e" => 4,
"f" => 5,
"g" => 6,
"h" => 7,
"i" => 8,
"j" => 9,
"k" => 10,
"l" => 11,
"m" => 12,
"n" => 13,
"o" => 14,
"p" => 15,
"q" => 16,
"r" => 17,
"s" => 18,
"t" => 19,
"u" => 20,
"v" => 21,
"w" => 22,
"x" => 23,
"y" => 24,
"z" => 25
);
function insert($string, $weight) {
$currentNode = $this->root;
$l = strlen($string);
for ($i = 0; $i < $l; $i++) {
$char = self::$asciiValues[$string[$i]];
$currentNode->weight = max($weight, $currentNode->weight);
if($currentNode->isChild($char)) {
$childNode = $currentNode->getChild($char);
} else {
$childNode = new TrieNode($weight);
$currentNode->addChild($char, $childNode);
}
$currentNode = $childNode;
}
}
function getNodeWeight($string) {
$currentNode = $this->root;
$l = strlen($string);
for ($i = 0; $i < $l; $i++) {
$char = self::$asciiValues[$string[$i]];
if (!$currentNode->isChild($char)) {
return -1;
}
$currentNode = $currentNode->getChild($char);
}
return $currentNode->weight;
}
}
$trie = new Trie();
//$handle = fopen('test.txt', 'r');
$handle = STDIN; // <- this is for the online judge
list($n, $q) = fscanf($handle, "%d %d");
for ($i = 0; $i < $n; $i++) { // insert data
list($s, $weight) = fscanf($handle, "%s %d");
$trie->insert($s, $weight);
}
for ($i = 0; $i < $q; $i++) { // query data
//$query = trim(strval(fgets($handle)));
$query = trim(strval(fgets($handle)));
echo $trie->getNodeWeight($query) . PHP_EOL;
}
fclose($handle);
?>
I would like to make a function that is able to generate a list of letters and optional numbers using a-z,0-9.
$output = array();
foreach(range('a','z') as $i) {
foreach(range('a','z') as $j) {
foreach(range('a','z') as $k) {
$output[] =$i.$j.$k;
}
}
}
Thanks
example:
myfunction($include, $length)
usage something like this:
myfunction('a..z,0..9', 3);
output:
000
001
...
aaa
aab
...
zzz
The output would have every possible combination of the letters, and numbers.
Setting the stage
First, a function that expands strings like "0..9" to "0123456789" using range:
function expand_pattern($pattern) {
$bias = 0;
$flags = PREG_SET_ORDER | PREG_OFFSET_CAPTURE;
preg_match_all('/(.)\.\.(.)/', $pattern, $matches, $flags);
foreach ($matches as $match) {
$range = implode('', range($match[1][0], $match[2][0]));
$pattern = substr_replace(
$pattern,
$range,
$bias + $match[1][1],
$match[2][1] - $match[1][1] + 1);
$bias += strlen($range) - 4; // 4 == length of "X..Y"
}
return $pattern;
}
It handles any number of expandable patterns and takes care to preserve their position inside your source string, so for example
expand_pattern('abc0..4def5..9')
will return "abc01234def56789".
Calculating the result all at once
Now that we can do this expansion easily, here's a function that calculates cartesian products given a string of allowed characters and a length:
function cartesian($pattern, $length) {
$choices = strlen($pattern);
$indexes = array_fill(0, $length, 0);
$results = array();
$resets = 0;
while ($resets != $length) {
$result = '';
for ($i = 0; $i < $length; ++$i) {
$result .= $pattern[$indexes[$i]];
}
$results[] = $result;
$resets = 0;
for ($i = $length - 1; $i >= 0 && ++$indexes[$i] == $choices; --$i) {
$indexes[$i] = 0;
++$resets;
}
}
return $results;
}
So for example, to get the output described in the question you would do
$options = cartesian(expand_pattern('a..z0..9'), 3);
See it in action (I limited the expansion length to 2 so that the output doesn't explode).
Generating the result on the fly
Since the result set can be extremely large (it grows exponentially with $length), producing it all at once can turn out to be prohibitive. In that case it is possible to rewrite the code so that it returns each value in turn (iterator-style), which has become super easy with PHP 5.5 because of generators:
function cartesian($pattern, $length) {
$choices = strlen($pattern);
$indexes = array_fill(0, $length, 0);
$resets = 0;
while ($resets != $length) {
$result = '';
for ($i = 0; $i < $length; ++$i) {
$result .= $pattern[$indexes[$i]];
}
yield $result;
$resets = 0;
for ($i = $length - 1; $i >= 0 && ++$indexes[$i] == $choices; --$i) {
$indexes[$i] = 0;
++$resets;
}
}
}
See it in action.
See this answer for a code that produces all possible combinations:
https://stackoverflow.com/a/8567199/1800369
You just need to add the $length parameter to limit the combinations size.
You can use a recursive function
assuming you mean it can be any number of levels deep, you can use a recursive function to generate an array of the permutations e.g.:
/**
* take the range of characters, and generate an array of all permutations
*
* #param array $range range of characters to itterate over
* #param array $array input array - operated on by reference
* #param int $depth how many chars to put in the resultant array should be
* #param int $currentDepth internal variable to track how nested the current call is
* #param string $prefix internal variable to know what to prefix the current string with
* #return array permutations
*/
function foo($range, &$array, $depth = 1, $currentDepth = 0, $prefix = "") {
$start = !$currentDepth;
$currentDepth++;
if ($currentDepth > $depth) {
return;
}
foreach($range as $char) {
if ($currentDepth === $depth) {
$array[] = $prefix . $char;
continue;
}
foo($range, $array, $depth, $currentDepth, $prefix . $char);
}
if ($start) {
return $array;
}
With the above function, initialize the return variable and call it:
$return = array();
echo implode(foo(range('a', 'z'), $return, 3), "\n");
And you're output will be all three char combinations from aaa, to zzz:
aaa
aab
...
zzy
zzz
The numeric parameter determins how recursive the function is:
$return = array();
echo implode(foo(range('a', 'z'), $return, 1), "\n");
a
b
c
...
Here's a live example.
$number= range(0, 9);
$letters = range('a', 'z');
$array= array_merge($number, $letters);
//print_r($array);
for($a=0;$a<count($array);$a++){
for($b=0;$b<count($array);$b++){
for($c=0;$c<count($array);$c++){
echo $array[$a].$array[$b].$array[$c]."<br>";
}
}
}
tested and working :)
I'm trying to make a function that is able to rotate through an array a given amount of times and then return the first index. But what I have is really slow and clunky. Take a look:
<?php
/**
* Get the current userid
* #return integer
*/
public function getCurrentUser( DateTime $startDate, DateInterval $interval, DateTime $endDate, $currentUser, $users, $rotating )
{
if ($rotating == 0)
{
return $currentUser;
}
$usrArray = array();
$dateRange = new DatePeriod( $startDate, $interval, $endDate);
// Push userIds to an array
foreach ($users as $user)
{
$usrArray[] = $user->id;
}
// Get the number of iterations from startDate to endDate
$steps = iterator_count($dateRange);
// Find the initial position of the orignal user
$key = array_search($currentUser, $usrArray);
// Set up the array so index 0 == currentUser
$usr = $usrArray;
array_splice($usr, $key);
$slice = array_slice($usrArray, $key);
$startList = array_merge($slice, $usr);
// Start rotating the array
for ($i=0; $i < $steps; $i++)
{
array_push($startList, array_shift($startList));
}
return $startList[0];
}
Here's an Xdebug profile before the PHP script timed out.
xdebug profile
Is there a better way to figure out who is index 0 after x amount of rotations?
Your array rotation is not that slow but it can be improved .. i believe this is your rotation code
Your code
// Start rotating the array
for ($i=0; $i < $steps; $i++)
{
array_push($startList, array_shift($startList));
}
return $startList[0];
You can remove the loop replace it with mod .. the way you can still get the same results here is the solution:
Solution
return $startList[ $steps % count($startList)];
You would get the same result .
Simple benchmark & Testing
$steps = 10000; <----------------- 10,000 steps
set_time_limit(0);
echo "<pre>";
$file = "log.txt";
// Using your current code
function m1($steps) {
$startList = range("A", "H");
for($i = 0; $i < $steps; $i ++) {
array_push($startList, array_shift($startList));
}
return $startList[0];
}
// Using InfiniteIterator
function m2($steps) {
$startList = range("A", "H");
$n = 0;
foreach ( new InfiniteIterator(new ArrayIterator($startList)) as $l ) {
if ($n == $steps) {
return $l;
break;
}
$n ++;
}
}
// Simple MOD solution
function m3($steps) {
$startList = range("A", "H");
return $startList[ $steps % count($startList)];
}
$result = array('m1' => 0,'m2' => 0,'m3' => 0);
for($i = 0; $i < 1; ++ $i) {
foreach ( array_keys($result) as $key ) {
$alpha = microtime(true);
$key($file);
$result[$key] += microtime(true) - $alpha;
}
}
echo '<pre>';
echo "Single Run\n";
print_r($result);
var_dump(m1($steps),m2($steps),m2($steps));
echo '</pre>';
Output
Single Run
Array
(
[m1] => 0.00012588500976562
[m2] => 0.00021791458129883
[m3] => 7.7962875366211E-5 <----------------- Mod solution fastest
)
string 'A' (length=1) |
string 'A' (length=1) |+------------- They all return same result
string 'A' (length=1) |