PHP loop isn't working, what am I doing wrong? - php

I am building a function that would receive 2 params, a string and a number.
it would basically print the first letters $n of $s.
I need to run a loop, please don't advise other non looping methods.
And yes, I need to keep the loop true throughout the function, it's suppose to close when the if is met.
For some reason the loop isn't closing, even though there's a return in the if condition that is being met when $stringCounter equals $n (=10 in this example.)
function printCounter($s, $n)
{
$stringCaller = '';
$stringCounter = strlen($stringCaller);
while (1) {
$stringCaller .= $s;
if ($stringCounter == $n) {
return $stringCaller;
}
}
}
printCounter('aba', '10');

You should imove the calc of $stringCounter inside the loop otherwise this never change
$stringCaller = '';
while (1) {
$stringCounter = strlen($stringCaller);
$stringCaller .= $s;
if ($stringCounter >= $n) {
return $stringCaller;
}
}

On my oppinion, TS is searching next approach:
function printCounter($s, $n)
{
$result = '';
$str_lenght = strlen($s);
if(!$str_lenght) {
return $result;
}
while (true) {
$result .= $s;
$result_lenght = strlen($result);
if($result_lenght/$str_lenght >= $n) {
return $result_lenght;
}
}
}
echo printCounter('aba', '10');
exit;

You can fix part of the issue by updating $stringCounter inside the loop.
function printCounter($s, $n)
{
$stringCaller = '';
while (1) {
$stringCaller .= $s;
$stringCounter = strlen($stringCaller); // check strlen after each addition of $s
if ($stringCounter == $n) {
return $stringCaller;
}
}
}
However, even after you fix that issue, there will still be cases where your loop will never exit (such as the example in your question) because $stringCounter can only equal $n if $n is a multiple of strlen($s).
For the example printCounter('aba', '10');
Iteration $stringCounter ($stringCounter == $n)
1 3 false
2 6 false
3 9 false
4 12 false
Obviously $stringCounter will only get farther away from $n from that point.
So to ensure that the function will exit, check for inequality instead with:
if ($stringCounter >= $n) {
If you need the function to return exactly $n characters, the function will need to be a little more complex and take a substring of $s to make up the remaining characters when $stringCounter + strlen($s) will be greater than $n, or return an $n character substring of your result like this:
function printCounter($s, $n)
{
$result = '';
while (1) {
$result .= $s;
if (strlen($result) >= $n) {
return substr($result, 0, $n);
}
}
}

Related

How to get the largest palindromic product PHP

First than nothing I'm not a native guy so sorry for all those mistakes.
I'm trying to get the largest palindromic product between two integers, for example; 3 and 11, the largest will be 11*11=121.
I tried with this.
function Pallendrome($str) : bool {
return (strval($str) == strrev(strval($str))) ? true : false;
}
function largestPalindromicProduct($lower, $upper) {
$array = array();
for($it=$upper; $it >= $lower; $it--){
for($it_=$upper; $it_ >= $lower; $it_--){
$num = $it*$it_;
if(Pallendrome($num)) { array_push($array, $num); }
}
}
if(empty($array)) { return NAN; }
else{ ksort($array); return $array[0];}
}
But, I'd need to get a way to optimize it 'cause it's taking a long time due to the numbers introduced in, are kind of big.
Do you guys have some idea for it? Thank ya!.
I'm sure the folks over at math.stackexchange.com could help you with a better algorithm, but for the purposes of optimizing what you've got thus far, here's a summation of all my comments:
function largestPalindromicProduct($lower, $upper)
{
$largest = 0;
for ($it = $upper; $it >= $lower; $it--) {
for ($it_ = $upper; $it_ >= $lower; $it_--) {
$num = $it * $it_;
// If we're on the first iteration and we have a product lower than the
// largest we've found so far, then we know we can never get a larger
// number (because we're counting down) and we can abort immediately.
if ($num <= $largest) {
if ($it_ == $upper) {
break 2;
}
// Otherwise, we can at least abort the rest of this subloop.
break;
}
// Only check if it's a palindrome once we've passed all the other checks.
if ($num == strrev($num)) {
$largest = $num;
}
}
}
return $largest;
}

PHP find Exponent after remainder is zero

I have this code written but I am having little issue or might be I am missing something,
public function test()
{
$number = "8192";
for ($i=1; $i<=32; $i++)
{
if(($number % pow(2,$i)) == 0)
{
$final = 32-$i;
echo $final;
}
}
exit;
}
I need to get which Exponent aka $i is used and then need to minus the value from 32 (or something else) to get the final results.
Since you want to compare the values just change the if condition, the modulus operator will not give you the exact result,
Here is the complete answer :
public function test()
{
$number = "8192";
for ($i=1; $i<=32; $i++)
{
if($number == pow(2,$i))
{
$final = 32-$i;
echo $final;
break;
}
}
exit;
}

Find the longest word given a dictionary

I'm reading overflow for years but never had to post anything (thanks to great answers) until now because i can't rly find solution for my problem.
I'm kinda new to PHP.
So I'm creating game where you have to find a longest word with 12 random generated letters. I actually did this successfully in C# and Java, but now I'm porting some of code to PHP because i'm working on multiplayer version and some stuff will be on server.
So i did all this using this great thread (Answer by Thomas Jungblut):
Find the longest word given a collection
Now i tried to do same in PHP but, it's weird for me. I get some crazy result's and i dont know how to replicate this java method in php:
arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
I'm not getting any error, but obvisuly thing is not working, is there anyone that can maybe help me to work this out?
UPDATE: BTW, i know post might be confusing im new to posting here...so forgive me ^^
I "fixed" code, it will now find me longest word. But there is bug somewhere. Bug is allowing algortithm to use one character more than once, which should not be possible.
I think problem is here:
$newDict[$index] = array_splice($allowedCharacters, $index +1, count($allowedCharacters) - ($index +1));
This is my Current Code:
parse_dictionary.php
<?php
$ouput = array();
$mysqli = new mysqli('localhost','root','','multiquiz_db');
$mysqli->set_charset('utf8');
if ($result = $mysqli->query("SELECT word FROM words_live")) {
while($row = $result->fetch_array(MYSQL_ASSOC)) {
//echo(mb_convert_encoding($row['word'], 'HTML-ENTITIES', 'utf-8'));
array_push($ouput, $row['word']);
}
//echo utf8_decode(json_encode($ouput));
}
$result->close();
$mysqli->close();
?>
Trie.php
<?php
class Trie
{
public $children = array();
public $value = null;
public $word = null;
public function __construct($value = null)
{
$this->value = $value;
}
public function adda($array)
{
$this->addb($array, 0);
}
public function addb($array, $offset)
{
foreach ($this->children as $child)
{
if($child->value == $array[$offset])
{
$child->addb($array, $offset + 1);
return;
}
}
$trieNode = new Trie($array[$offset]);
array_push($this->children, $trieNode);
if($offset < count($array) - 1)
{
$trieNode->addb($array, $offset+1);
}
else
{
$trieNode->word = implode(" ", $array);
}
}
}
?>
Index.php
<?php
include 'Trie.php';
include 'parse_dictionary.php';
ini_set('memory_limit', '1024M'); // or you could use 1G
header('Content-Type: text/html; charset=utf-8');
mb_internal_encoding("UTF-8");
class LongestWord
{
public $root = null;
public function __construct($ouput)
{
$this->root = new Trie();
foreach ($ouput as $word)
{
//echo($word);
//echo(str_split_unicode($word)[0]);
$this->root->adda(str_split_unicode($word));
}
}
public function search($cs)
{
return $this->visit($this->root, $cs);
}
function visit($n, $allowedCharacters)
{
$bestMatch = null;
if(count($n->children) == 0)
{
$bestMatch = $n->word;
}
foreach($n->children as $child)
{
if($this->contains($allowedCharacters, $child->value))
{
$result = $this->visit($child, $this->remove($allowedCharacters, $child->value));
if($bestMatch == null || $result != null && strlen($bestMatch) < strlen($result))
{
$bestMatch = $result;
}
}
}
return $bestMatch;
}
function remove($allowedCharacters, $value)
{
$newDict = $allowedCharacters;
if(($key = array_search($value, $newDict)))
{
unset($newDict[$key]);
}
return $newDict;
}
function contains($allowedCharacters, $value)
{
foreach($allowedCharacters as $x)
{
if($value == $x)
{
// echo $value . "=====". $x. "|||||||";
return true;
}
else
{
//echo $value . "!!===". $x. "|||||||";
}
}
return false;
}
}
function str_split_unicode($str, $l = 0) {
if ($l > 0) {
$ret = array();
$len = mb_strlen($str, "UTF-8");
for ($i = 0; $i < $len; $i += $l) {
$ret[] = mb_substr($str, $i, $l, "UTF-8");
}
return $ret;
}
return preg_split("//u", $str, -1, PREG_SPLIT_NO_EMPTY);
}
$chars = 'IIOIOFNČGDĆJ';
$testCharacters = str_split_unicode($chars);
$lw = new LongestWord($ouput);
echo($lw->search($testCharacters));
?>
As you're using MySQL, here's an approach that will let the DB server do the work.
It's a bit dirty, because you have to add several WHERE conditions with regex matching, which will have a rather poor performance. (Unfortunately, I could not come up with a regex that would require all of the letters in one expression, but I'd be happy to be corrected.)
However, I have tested it on a database table of >200000 entries; it delivers results within less than 0.3 sec.
SELECT word
FROM words_live
WHERE
word REGEXP "a" AND
word REGEXP "b" AND
word REGEXP "c" AND
word REGEXP "d"
ORDER BY LENGTH(word) DESC
LIMIT 1;
Obviously, you must generate one word REGEXP "a" condition per letter in your PHP code when constructing the query.
The query should then give you exactly one result, namely the longest word in the database containing all of the characters.
I solved problem with this function, full working code updated in question post
function remove($allowedCharacters, $value)
{
$newDict = $allowedCharacters;
if(($key = array_search($value, $newDict)))
{
unset($newDict[$key]);
}
return $newDict;
}
removed old one:
function remove($allowedCharacters, $value)
{
$newDict = [count($allowedCharacters) - 1];
$index = 0;
foreach($allowedCharacters as $x)
{
if($x != $value)
{
$newDict[$index++] = $x;
}
else
{
//we removed the first hit, now copy the rest
break;
}
}
//System.arraycopy(allowedCharacters, index + 1, newDict, index, allowedCharacters.length - (index + 1)); JAVA arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
//$newDict[$index] = array_splice($allowedCharacters, $index +1, count($allowedCharacters) - ($index +1));
//$newDict = $allowedCharacters;
return $newDict;
}

Rewrite a large number of for loops into something shorter

I have the following code:
for($a=1; $a<strlen($string); $a++){
for($b=1; $a+$b<strlen($string); $b++){
for($c=1; $a+$b+$c<strlen($string); $c++){
for($d=1; $a+$b+$c+$d<strlen($string); $d++){
$tempString = substr_replace($string, ".", $a, 0);
$tempString = substr_replace($tempString, ".", $a+$b+1, 0);
$tempString = substr_replace($tempString, ".", $a+$b+$c+2, 0);
$tempString = substr_replace($tempString, ".", $a+$b+$c+$d+3, 0);
echo $tempString."</br>";
}
}
}
}
What it does is to make all possible combinatons of a string with several dots.
Example:
t.est123
te.st123
tes.t123
...
test12.3
Then, I add one more dot:
t.e.st123
t.es.t123
...
test1.2.3
Doing the way I'm doing now, I need to create lots and lots of for loops, each for a determined number of dots. I don't know how I can turn that example into a functon or other easier way of doing this.
Your problem is a combination problem. Note: I'm not a math freak, I only researched this information because of interest.
http://en.wikipedia.org/wiki/Combination#Number_of_k-combinations
Also known as n choose k. The Binomial coefficient is a function which gives you the number of combinations.
A function I found here: Calculate value of n choose k
function choose($n, $k) {
if ($k == 0) {return 1;}
return($n * choose($n - 1, $k - 1)) / $k;
}
// 6 positions between characters (test123), 4 dots
echo choose(6, 4); // 15 combinations
To get all combinations you also have to choose between different algorithms.
Good post: https://stackoverflow.com/a/127856/1948627
UPDATE:
I found a site with an algorithm in different programming languages. (But not PHP)
I've converted it to PHP:
function bitprint($u){
$s= [];
for($n= 0;$u > 0;++$n, $u>>= 1) {
if(($u & 1) > 0) $s[] = $n;
}
return $s;
}
function bitcount($u){
for($n= 0;$u > 0;++$n, $u&= ($u - 1));
return $n;
}
function comb($c, $n){
$s= [];
for($u= 0;$u < 1 << $n;$u++) {
if(bitcount($u) == $c) $s[] = bitprint($u);
}
return $s;
}
echo '<pre>';
print_r(comb(4, 6));
It outputs an array with all combinations (positions between the chars).
The next step is to replace the string with the dots:
$string = 'test123';
$sign = '.';
$combs = comb(4, 6);
// get all combinations (Th3lmuu90)
/*
$combs = [];
for($i=0; $i<strlen($string); $i++){
$combs = array_merge($combs, comb($i, strlen($string)-1));
}
*/
foreach ($combs as $comb) {
$a = $string;
for ($i = count($comb) - 1; $i >= 0; $i--) {
$a = substr_replace($a, $sign, $comb[$i] + 1, 0);
}
echo $a.'<br>';
}
// output:
t.e.s.t.123
t.e.s.t1.23
t.e.st.1.23
t.es.t.1.23
te.s.t.1.23
t.e.s.t12.3
t.e.st.12.3
t.es.t.12.3
te.s.t.12.3
t.e.st1.2.3
t.es.t1.2.3
te.s.t1.2.3
t.est.1.2.3
te.st.1.2.3
tes.t.1.2.3
This is quite an unusual question, but I can't help but try to wrap around what you are tying to do. My guess is that you want to see how many combinations of a string there are with a dot moving between characters, finally coming to rest right before the last character.
My understanding is you want a count and a printout of string similar to what you see here:
t.est
te.st
tes.t
t.es.t
te.s.t
t.e.s.t
count: 6
To facilitate this functionality I came up with a class, this way you could port it to other parts of code and it can handle multiple strings. The caveat here is the strings must be at least two characters and not contain a period. Here is the code for the class:
class DotCombos
{
public $combos;
private function combos($string)
{
$rebuilt = "";
$characters = str_split($string);
foreach($characters as $index => $char) {
if($index == 0 || $index == count($characters)) {
continue;
} else if(isset($characters[$index]) && $characters[$index] == ".") {
break;
} else {
$rebuilt = substr($string, 0, $index) . "." . substr($string, $index);
print("$rebuilt\n");
$this->combos++;
}
}
return $rebuilt;
}
public function allCombos($string)
{
if(strlen($string) < 2) {
return null;
}
$this->combos = 0;
for($i = 0; $i < count(str_split($string)) - 1; $i++) {
$string = $this->combos($string);
}
}
}
To make use of the class you would do this:
$combos = new DotCombos();
$combos->allCombos("test123");
print("Count: $combos->combos");
The output would be:
t.est123
te.st123
tes.t123
test.123
test1.23
test12.3
t.est12.3
te.st12.3
tes.t12.3
test.12.3
test1.2.3
t.est1.2.3
te.st1.2.3
tes.t1.2.3
test.1.2.3
t.est.1.2.3
te.st.1.2.3
tes.t.1.2.3
t.es.t.1.2.3
te.s.t.1.2.3
t.e.s.t.1.2.3
Count: 21
Hope that is what you are looking for (or at least helps)....

PHP: Caching ordered integer partition algorithm

First: The problem's name in Wikipedia is "ordered partition of a set".
I have an algorithm which counts possible partitions. To speed it up, I use a cache:
function partition($intervalSize, $pieces) {
// special case of integer partitions: ordered integer partitions
// in Wikipedia it is: ordered partition of a set
global $partition_cache;
// CACHE START
$cacheId = $intervalSize.'-'.$pieces;
if (isset($partition_cache[$cacheId])) { return $partition_cache[$cacheId]; }
// CACHE END
if ($pieces == 1) { return 1; }
else {
$sum = 0;
for ($i = 1; $i < $intervalSize; $i++) {
$sum += partition(($intervalSize-$i), ($pieces-1));
}
$partition_cache[$cacheId] = $sum; // insert into cache
return $sum;
}
}
$result = partition(8, 4);
Furthermore, I have another algorithm which shows a list of these possible partitions. But it doesn't use a cache yet and so it's quite slow:
function showPartitions($prefix, $start, $finish, $numLeft) {
global $partitions;
if ($numLeft == 0 && $start == $finish) { // wenn eine Partition fertig ist dann in Array schreiben
$gruppen = split('\|', $prefix);
$partitions[] = $gruppen;
}
else {
if (strlen($prefix) > 0) { // nicht | an Anfang setzen sondern nur zwischen Gruppen
$prefix .= '|';
}
for ($i = $start + 1; $i <= $finish; $i++) {
$prefix .= chr($i+64);
showPartitions($prefix, $i, $finish, $numLeft - 1);
}
}
}
$result = showPartitions('', 0, 8, 4);
So I have two questions:
1) Is it possible to implement a cache in the second algorithm, too? If yes, could you please help me to do this?
2) Is it possible to write the results of the second algorithm into an structured array instead of a string?
I hope you can help me. Thank you very much in advance!
PS: Thanks for the two functions, simonn and Dan Dyer!
No, I don't think a cache will help you here because you're never actually performing the same calculation twice. Each call to showPartitions() has different parameters and generates a different result.
Yes, of course. You're basically using another level of nested arrays pointing to integers to replace a string of characters separated by pipe characters. (Instead of "A|B|C" you'll have array(array(1), array(2), array(3)).)
Try changing showPartitions() as such:
if ($numLeft == 0 && $start == $finish) { // wenn eine Partition fertig ist dann in Array schreiben
$partitions[] = $prefix;
}
else {
$prefix[] = array();
for ($i = $start + 1; $i <= $finish; $i++) {
$prefix[count($prefix) - 1][] = $i;
showPartitions($prefix, $i, $finish, $numLeft - 1);
}
}
and instead of calling it with an empty string for $prefix, call it with an empty array:
showPartitions(array(), 0, 8, 4);
Off topic: I rewrote the first function to be a little bit faster.
function partition($intervalSize, $pieces) {
// special case of integer partitions: ordered integer partitions
// in Wikipedia it is: ordered partition of a set
// CACHE START
static $partition_cache = array();
if (isset($partition_cache[$intervalSize][$pieces])) {
return $partition_cache[$intervalSize][$pieces];
}
// CACHE END
if ($pieces === 1) {
return 1;
}
if ($intervalSize === 1) {
return 0;
}
$sum = 0;
$subPieces = $pieces - 1;
$i = $intervalSize;
while (--$i) {
$sum += partition($i, $subPieces);
}
$partition_cache[$intervalSize][$pieces] = $sum; // insert into cache
return $sum;
}
Although this is a bit old, nevertheless,
a PHP Class which implements various combinatorics/simulation methods including partitions/permutations/combinations etc.. in an efficient way
https://github.com/foo123/Simulacra/blob/master/Simulacra.php
PS: i am the author

Categories