Retrieving anagrams in PHP - php

I am trying to create a basic anagram generator in PHP.
The code below works with whole words, i. e. shuffling n times the chars of an input string ($word) and checking each shuffled string in a dictionary.
Whenever a match is found, the anagram is saved in an array ($out).
// here I read a text file, line by line, containing all the acceptable words
$dictionary = file('./docs/dictionary.txt',FILE_IGNORE_NEW_LINES);
//here I collect the word to make the anagram of
$word = mysql_real_escape_string(strtolower($_POST["word"]));
$times = 100;
// here I create an empty array where I can store all the anagrams of $word
$out = array();
for ($k = 0 ; $k < $times; $k++){
$string = str_shuffle($word);
if (in_array($string, $dictionary)){
array_push($out, $string);
}
}
$out = array_unique($out);
// now I print all the anagrams that have been stored in $out
foreach($out as $key => $value){
echo "I have found the anagram ".$value.".";
}
This trivial approach works using all the chars of the input string.
Now I want to search for partial anagrams too, removing randomly some chars from the initial string and matching these partial strings to the words in my dictionary.
I tried to proceed as follows, but I got lost in the process:
// here I create an empty array where I can later store the partial anagrams
$outpartial = array();
// Here I check how long the initial input string is
$length = strlen($string);
$num = 1;
// now I remove a char from the initial string in every loop and search for anagrams using the other chars which have been kept
while($num < $length){
$letters = $length - $num;
$removed = substr($string,-$num);
$kept = substr($string,0,$letters);
for ($i = 0 ; $i < $times; $i++){
$keptchars = str_shuffle($kept);
if (in_array($keptchars, $dictionary)){
array_push($outpartial, $keptchars);
}
}
$outpartial = array_unique($outpartial);
foreach($outpartial as $k => $v){
echo "Using the chars ".$kept." - ignoring ".$removed." - I have found the partial anagram ".$v.".";
}
$num++;
}
This part does not work as planned: the while loop above does not retrieve partial anagrams. It removes one char only from the initial string.

**You can try this out as per my example**
function funwithAnagrams($text){
for ($i = 0; $i < count($text); $i++) {
for($j = count($text) - 1; $j > $i; $j--) {
$sortedA = str_split(sort($text[$i]));
$sortedB = str_split(sort($text[$j]));
if($sortedA == $sortedB) {
// splice the array at index $j
array_splice($text, $j, 1);
}
}
}
return sort($text);
}

Related

Simulating leftTrim function in PHP

Here I am trying to simulate built in function "ltrim" (that strips characters from the beginning of the string) in PHP
here is the code I have written
function leftTrim(string $Sstr, mixed $char) : string
{
$i = 0;
for(; $i< strlen($Sstr); $i++): // loop on the string
for($j=0; $j <strlen($char); $j++): // loop on the characters
if($Sstr[$i] === $char[$j])
{
$Sstr[$i] = " ";
break;
}
endfor;
endfor;
return $Sstr;
}
but I found two problems with this code:
it replaces each character with a space character that means
that the length of the code remains the same.
this function trims characters from the middle of the string
where it should only trim from the beginning.
Don't replace the characters with spaces. Just find the index of the first non-matching character, then use substr() to get all the characters after that into the result.
Stop looping when you find a character that isn't in $char.
There's no need for the inner loop, you can use strpos() to check if a character is in $char.
function leftTrim(string $Sstr, mixed $char) : string
{
for($i = 0; $i< strlen($Sstr); $i++): // loop on the string
if (strpos($char, $Sstr[$i]) === false) {
break;
}
endfor;
return substr($Sstr, $i);
}
Barmar's answer is the correct one (by correcting and improving the OPs code).
One alternative would be to split the string to an array and unset the characters to be trimmed and then join the remaining characters back to a string:
function leftTrim(string $str, string $chars = ' '): string {
$splitted = str_split($str);
for ($i = 0; $i < count($splitted); $i++) {
if (str_contains($chars, $splitted[$i])) {
unset($splitted[$i]);
} else {
break;
}
}
return implode('', $splitted);
}

WP custom field contains 50 names separated by comma: how to just list the first 5?

As stated in the title, in my blog, I own a custom field that - for each post - contains 50 names, but it's way too much, so I'd like to just echo the first 5 names.
I'm trying with this, but it's not working properly...Where am I going wrong?
<?php
$players = get_post_meta($post->ID, 'Names_List', true);
$i = 1;
foreach($players as $player) {
if ($i < 6) {
echo $player;
}
$i++;
}
?>
You are trying to iterate through a string. This means that when you access $players[2] you will get the third character in the string $players.
You will need to convert the string into an array by using the explode function which will break the string into an array based on a character you tell it.
$string = 'This is a string, This is a string 2';
$array = explode(',', $string);
This will break the string into parts based on a comma, resulting in array as follows:
[ 'This is a string', 'This is a string 2' ]
Once you have turned your string into an array, you can then loop through the first 5 by using a for loop and setting it up to only run 5 times.
for($i = 0; $i < 5; $i++) { ... }
This will run the code between the brackets 5 times as we are saying:
Starting $i at 0, whilst $i is less than 5 - Run the code.
After running the code, $i++ will add 1 to $i and test the condition again.
The following code should be able to replace the code from the question and give you the results you want.
$players = get_post_meta($post->ID, 'Names_List', true);
$players_array = explode(',', $players);
for($i = 0; $i < 5; $i++) {
echo $players_array[$i];
if($i < 4) {
echo ',';
}
}
You can use array_slice to get first 5 elements.
Obviously you need to split the string by the comma delimiter with explode first
$players = get_post_meta($post->ID, 'Names_List', true);
$players_array = explode(',', $players);
$first_five = array_slice($players_array, 0, 5);
foreach($first_five as $player)
{
echo $player;
}

How to display specific letters from a list of words in a loop?

I received this challenge in an interview and I would like some help solving it.
Using the input string: PHP CODING TECH, produce the following output.
PCT
PHCT
PHPCT
PHPCOT
PHPCODT
PHPCODIT
PHPCODINT
PHPCODINGT
PHPCODINGTE
PHPCODINGTEC
PHPCODINGTECH
As I understand it, the logic is to explode the input string on the spaces and then in a loop structure, display the leading letter(s) of each word as a single string. During each iteration (after the first), the earliest incomplete word displays an additional leading letter.
This is my coding attempt:
$str = "PHP CODING TECH";
$a = explode(' ', $str);
for ($i=0; $i < count($a); $i++) {
for ($j=0; $j < strlen($a[$i]) ; $j++) {
//echo "<pre>";
$b[$i][$j] = explode(' ', $a[$i][$j]);
}
}
echo "<pre>";
print_r($b);
Code: (Demo) (or with DO-WHILE())
$input = "PHP CODING TECH";
$counters = array_fill_keys(explode(' ', $input), 1); // ['PHP' => 1, 'CODING' => 1, 'TECH' => 1]
$bump = false; // permit outer loop to run
while (!$bump) { // while still letters to output....
$bump = true; // stop after this iteration unless more letters to output
foreach ($counters as $word => &$len) { // $len is mod-by-ref for incrementing
echo substr($word, 0, $len); // echo letters using $len
if ($bump && isset($word[$len])) { // if no $len has been incremented during inner loop...
++$len; // increment this word's $len
$bump = false; // permit outer loop to run again
}
}
echo "\n"; // separate outputs
}
Output:
PCT
PHCT
PHPCT
PHPCOT
PHPCODT
PHPCODIT
PHPCODINT
PHPCODINGT
PHPCODINGTE
PHPCODINGTEC
PHPCODINGTECH
Explanation:
I am generating an array of words and initial lengths from the exploded input string. $bump is dual-purpose; it not only controls the outer loop, it also dictates the word which gets a length increase within the inner loop. $len is "modifiable by reference" so that any given word's $len value can be incremented and stored for use in the next iteration. isset() is used on $word[$len] to determine if the current word has more available letters to output in the next iteration; if not, the next word gets a chance (until all words are fully displayed).
And while I was waiting for this page to be reopened, I whacked together an alternative method:
$input = "PHP CODING TECH";
$words = explode(' ', $input); // generates: ['PHP', 'CODING', 'TECH']
$master = ''; // initialize for first offset and then concatenation
foreach ($words as $word) {
$offsets[] = strlen($master); // after loop, $offsets = [0, 3, 9]
$master .= $word; // after loop, $master = 'PHPCODINGTECH'
}
$master_offsets = range(0, strlen($master)); // generates: [0,1,2,3,4,5,6,7,8,9,10,11,12]
do {
foreach ($offsets as $offset) {
echo $master[$offset];
}
echo "\n";
} while ($master_offsets !== ($offsets = array_intersect($master_offsets, array_merge($offsets, [current(array_diff($master_offsets, $offsets))])))); // add first different offset from $master_offsets to $offsets until they are identical

What is the most efficient way to parse the specific segments of a URL path?

Say my url is www.example.com/usa/california/redding/
What is the most efficient way to return the following:
$urls = array ( 0 => '/usa/', 1 => '/usa/california/', 2 => '/usa/california/redding/' );
The actual URL will be unknown and the length / number of segments will be unknown.
The most efficient way to do this would be to loop over the string, looking each consecutive / character and then pushing them onto an array as you go. This algorithm will be O(n) assuming string concatenation is also O(n).
$url = "www.example.com/usa/california/redding/";
$next = "";
$urls = array();
// we use the strpos function to get position of the first /
// this let's us ignore the host part of the url
$start = strpos($url, "/");
// just in case PHP uses C strings or something (doubtful)
$length = strlen($url);
// loop over the string, taking one character at a time
for ($i = $start; $i < $length; $i++) {
// append the character to our temp string
$next .= $url[$i];
// skip the first slash, but after that push the value of
// next onto the array every time we see a slash
if ($i > $start && $url[$i] == "/") {
array_push($urls, $next);
}
}
Not too elegant, but this gets the job done:
<?php
$link = 'www.example.com/usa/california/redding/';
$parts = explode('/',$link);
$results = array();
for ($i = 1; $i < count($parts) - 1; $i++) {
$results[] = '/'.implode('/', array_slice($parts, 1,$i)).'/';
}
print_r($results);
?>
To use the regular expression is the first though came to me, but i know it might not be efficient:
$str = 'www.example.com/usa/california/redding/';
$patten = '/(((\/.[0-9A-Za-z]+\/).[0-9A-Za-z]+\/).[0-9A-Za-z]+\/)/';
$ret = preg_match($patten, $str, $matches);
var_export($matches);
the output will be:
array (
0 => '/usa/california/redding/',
1 => '/usa/california/redding/',
2 => '/usa/california/',
3 => '/usa/',
)
first is the whole match, the remain 3 is the capture.

Scrabble word generator

After watching my brother cheating in an iphone game like scrabble I was wondering what was the algotithm behing it.
Given some letters: A B C T E E
And SQL table full of correct words.
How would I create all combinations of letters for making afterwars a select like:
Select * from words where word IN ('A','AT',...), just to take from those combinations the ones that are correct ?¿
Another possible way could be a SQL table with every letter in a column for each word.
But afterwards the system should verify that any word form the select has more time the same letter given.
Ex:
c1 c2 c3 c4
t e e
a i r
This question is just for feeding curiosity, and learning witch algorithm it might be used in for creating all those combinations (with full and partial given letters) to check afterwards if they exist.
Thanks!
font: http://icon.cat/worder/wordsfinder
To find all possible valid word this are the following steps
Find all possible combination
Find each permutation for each word in the combination
Search Database for the words
List the words
Script
$tiles = array( "A", "B", "C", "T", "E", "E") ;
$words = array();
$set = powerSet($tiles,2);
$mysql = new mysqli("localhost","root","","word");
$sql = "SELECT id from dic WHERE word = '%s'" ;
foreach ($set as $key => $value)
{
$word = implode("", $value);
$wordPermutation = permute($word);
foreach($wordPermutation as $keyWord)
{
if(!in_array($keyWord, $words))
{
//if($result = $mysql->query(sprintf($sql,$keyWord)))
//{
//var_dump(sprintf($sql,$keyWord));
//if($result->num_rows > 0)
//{
$words[] = $keyWord ;
//}
//}
}
}
}
print_r($words);
Functions
function powerSet($in, $minLength = 1, $max = 10) {
$count = count ( $in );
$members = pow ( 2, $count );
$return = array ();
for($i = 0; $i < $members; $i ++) {
$b = sprintf ( "%0" . $count . "b", $i );
$out = array ();
for($j = 0; $j < $count; $j ++) {
if ($b {$j} == '1')
$out [] = $in [$j];
}
if (count ( $out ) >= $minLength && count ( $out ) <= $max) {
$return [] = $out;
}
}
return $return;
}
function permute($str) {
if (strlen($str) < 2) {
return array($str);
}
$permutations = array();
$tail = substr($str, 1);
foreach (permute($tail) as $permutation) {
$length = strlen($permutation);
for ($i = 0; $i <= $length; $i++) {
$permutations[] = substr($permutation, 0, $i) . $str[0] . substr($permutation, $i);
}
}
return $permutations;
}
Please note that i commented out the database verification section so that the demo can work
See Demo
http://codepad.viper-7.com/oG6E6w
I would try something like
WHERE (word like '%A%' and not word like '%A%A%')
AND (word like '%B%' and not word like '%B%B%')
and so on. But I'm sure there must be more professional solutions!
I finally got it working.
If someone is ever interested on making a self word generator, this is how I made it.
MySQL, a table with:
[id] , [Word]
a view for each length:
V1 = Select Word from TABLE where LENGTH(Word) = 1
V2 = Select Word from TABLE where LENGTH(Word) = 2
[...]
php side:
Using the functions of baba, I made an array where: array[2] are the combinations of letters that have a length of 2, and so on.
Finally all i had to do is a Select for each array to the view like
Select Word from V3 where Word like ('asd','dsa',....);
There must be a faster way, but with a less than a second (localhost) and word diccionary of 700K made its way.
A better way to achieve unscrambling is to use anagrams. So instead of having a library of all the possible words, use an associative array using the letters that make up the words as the index.
anagram['aer'] = ['are', 'ear', 'era']
To implement this, loop through all of your dictionary words and push each one into an array where the index is the letters of the word in alphabetical order.
for(var i = 0; i < dictionary.length; i++) {
//Loop through dictionary array
var str = words[i].split('').sort().join('');
//break apart the word and sort it alphabetically
if(!anagram[str]) {
//check if there is already an index with that same anagram
anagram[str] = [];
}
anagram[str].push(words[i]);
//Add the word to the anagram array
}
This way allows you to quickly index the library without going through thousands of possible permutations.
An example of this method in javascript: Word Unscrambler
Here is great article about World fastest scrabble program
You just should have some knowledge in Descrete Math(Word Automats). Hope it will help you :)

Categories