php need all posible changed values - php

I need to change each character in a string but this change is include all possible results. Keys and Values of array variable can replace each other
for example list of all letter is similar to below
$changeList=array(
"ş"=>"s",
"ç"=>"c",
"i"=>"ı",
"ğ"=>"ğ",
"ü"=>"u",
"ö"=>"o",
"Ş"=>"S",
"Ç"=>"C",
"İ"=>"I",
"Ğ"=>"G",
"Ü"=>"U",
"Ö"=>"O"
);
$word="ağaç";
if I calculated correct , this is posible 2^2 = 4 results. (for ğ and ç letters)
after replace all letters , I need this results.
ağaç
agaç
ağac
agac
and other words example =pişir
this words include changeable three letter. 2^3 = 8 results. (for s,ı,ç 3 letters)
pişir
pışir
pisir
pişır
pişır
pisır
pısır
pışır
I need an array variable which contains all results. How can I do this , with best performance.

Okay, I became a little obsessed with this and decided to have a go (hey, it's Friday evening).
As I noted in the comment above, you want to generate a new word variation for each individual letter change - including letters that occur more than once. Another tricky consideration is multibyte characters.
What follows is an attempt an an answer that is probably pretty sub-optimal but hopefully gets the job done... I'm sure there are many ways to improve this but it's a start that you might be able to iterate on:
<?php
// this solution assumes UTF-8 config settings in php.ini
// setting them with ini_set() seems to work also but ymmv
ini_set('default_charset', 'UTF-8');
ini_set('mbstring.internal_encoding', 'UTF-8');
function getWordReplacements($word, $replacements) {
// $results... add the original
$results = array($word);
// multibyte split of $word
// credit: http://stackoverflow.com/a/2556753/312962
$chars = preg_split('//u', $word, -1, PREG_SPLIT_NO_EMPTY);
// we will iterate over the chars and create replacements twice,
// first pass is a forward pass, second is a reverse pass
// we need a copy of the $chars array for each pass
$forwardPass = $chars;
$reversePass = $chars;
// how many chars in the word?
$length = count($chars);
// we'll store the index of the first character
// that has a copy in the $replacements list for later
$first = null;
// first pass... iterate!
for ($i = 0; $i < $length; $i++) {
// is the current character in the $replacements list?
if (array_key_exists($chars[$i], $replacements)) {
// save the index of the first match
if (is_null($first)) {
$first = $i;
}
// replace the found char with the translation
$forwardPass[$i] = $replacements[$forwardPass[$i]];
// flatten the result and save it as a variation
$results[] = implode($forwardPass);
}
}
// second pass... same as the first pass except:
// * we go backwards through the array
// * we stop before we reach the $first index, to avoid a duplicate
// entry of the first variation saved in the first pass...
for ($j = ($length - 1); $j > $first; $j--) {
if (array_key_exists($chars[$j], $replacements)) {
$reversePass[$j] = $replacements[$reversePass[$j]];
$results[] = implode($reversePass);
}
}
// return the results
return $results;
}
// test with a subset replacement list
$list = [
'ç' => 'c',
'ğ' => 'g',
'ş' => 's',
'i' => 'ı',
];
// a couple of examples
$r1 = getWordReplacements('pişir', $list);
$r2 = getWordReplacements('ağaç', $list);
var_dump($r1, $r2);
Yields:
array (size=6)
0 => string 'pişir' (length=6)
1 => string 'pışir' (length=7)
2 => string 'pısir' (length=6)
3 => string 'pısır' (length=7)
4 => string 'pişır' (length=7)
5 => string 'pisır' (length=6)
array (size=4)
0 => string 'ağaç' (length=6)
1 => string 'agaç' (length=5)
2 => string 'agac' (length=4)
3 => string 'ağac' (length=5)
Hope this helps :)

Related

How to check if words can be created from list of letters?

I have a string $raw="aabbcdfghmnejaachto" and an array $word_array=array('cat','rat','goat','total','egg').
My program needs to check whether it is possible to make the words in the array with letters from the string. There is one extra condition; if the word contains a letter occurring more than once, that letter must occur at least the same number of times in the string.
E.g. egg. There are two g's. If the string $raw doesn't contain two g's, then it's not possible to make this word.
This is my expected result:
Array([cat]=>'Yes',[rat]=>'No',[goat]=>'Yes',[total]=>'No',[egg]=>'No')
I tried the following, but it doesn't output the expected result:
$res=array();
$raw="aabbcdfghmnejaachto";
$word_array=array('cat','rat','goat','total','egg');
$raw_array= str_split($raw);
foreach($word_array as $word=>$value)
{
$word_value= str_split($value);
foreach($word_value as $w=>$w_value)
{
foreach($raw_array as $raw=>$raw_value)
{
if(strcmp($w_value,$raw_value)==0)
{
$res[$value]='Yes';
}
else
{
$res[$value]='No';
}
}
}
}
print_r($res);
EDIT: The code, as originally posted, was missing the letter e from the string $raw so the egg example would actually return No. I have updated the Question and all the Answers to reflect this. - robinCTS
You must loop through each word/element in the $words array, then loop again through each character of each word.
Upon each iteration of the outer loop, set the default result value to Yes.
Then you must iterate each unique character of the current word. (array_count_values())
Check if the number of occurrences of the current character in the word is greater than the number of occurrences of the current character in the string of letters.
*As a matter of performance optimization, array_count_values() is used on the inner loop to avoid any unnecessary iterations of duplicate letters in $word. The $count variable saves having to make two substr_count() calls in the if statement.
Code: (Demo)
$string = "aabbcdfghmnejaachto";
$words = array('cat','rat','goat','total','egg');
foreach ($words as $word) { // iterate each word
$result[$word]='Yes'; // set default result value
foreach (array_count_values(str_split($word)) as $char=>$count) { // iterate each unique letter in word
if ($count > substr_count($string, $char)) { // compare current char's count vs same char's count in $string
$result[$word]='No'; // if more of the character in word than available in $string, set No
break; // make early exit from inner loop, to avoid unnecessary iterations
}
}
}
var_export($result);
This is the output :
array (
'cat' => 'Yes',
'rat' => 'No',
'goat' => 'Yes',
'total' => 'No',
'egg' => 'No',
)
BIG THANKYOU to mickmackusa for hijacking significantly enhancing this answer.
Your problem is you are not counting the number of times each character occurs in the $raw array, you are just checking each character in each of the words to see if that character exists in $raw. Unless you put in some form of counting, or else make a copy of $raw for each word and remove letters as they are used, you are not going to be able to do this.
I have counted occurrences of characters in string and compare that number of occurrence! You can find this answer working!!!
$res=array();
$raw="aabbcdfghmnejaachto"; //tgrel -- to make all yes
$res=array();
$word_array=array('cat','rat','goat','total','egg');
$raw_array= str_split($raw);
$count_raw = array_count_values($raw_array);
foreach($word_array as $value)
{
$word_value= str_split($value);
$newArray = array_count_values($word_value);
$res[$value]='yes';
foreach($newArray as $char=>$number){
if(!isset($count_raw[$char]) || $count_raw[$char]<$number){
$res[$value]='No';
break;
}
}
}
print_r($res);
Your error here is obvious, that you decided whether a value a word is accepted or not on individual tests of characters, while it should be based on the all the letter of the word , you don't need to precise both the key and value of an array if you need only its value
as in
foreach($word_array as $value)
then I've found that the use of the function in_array(), make the code much clearer
$res=array();
$raw="aabbcdfghmnejaachto";
$res=array();
$word_array=array('cat','rat','goat','total','egg');
$raw_array= str_split($raw);
foreach($word_array as $value)
{
$word_value= str_split($value);
$res[$value]='yes';
foreach($word_value as $w_value)
{
if (!in_array($w_value,$raw_array))
$res[$value]='No';
}
}
print_r($res);
Lets try to make it w/o loops, but with closures:
$raw = "aabbcdfghmnejaachto";
$word_array = ['cat', 'rat', 'goat', 'total', 'egg'];
$result = [];
$map = count_chars($raw, 1);
array_walk(
$word_array,
function ($word) use ($map, &$result) {
$result[$word] = !array_udiff_assoc(
count_chars($word, 1), $map, function ($i, $j) { return $i > $j; }
) ? 'Yes' : 'No';
}
);
We are building a map of symbols, used in original string with count_chars($raw, 1), so it will look like this.
$map:
[
97 => 4, // "97" is a code for "a"; and "4" - occurrence number.
98 => 2,
...
]
array_walk goes through words and adds each of them in a final $result with a Yes or No values that come from a comparison with a map, that was built for a word.
array_udiff_assoc compares two maps, throwing away those elements that have the same key and values bigger for an original map (comparing with a map for a word). Also array_udiff_assoc() returns an array containing all the values from array1 that are not present in any of the other arguments, so the final step is a negation operation preceding array_udiff_assoc.
Demo
Try this
$res=array();
$word_array=array('cat','rat','goat','total','egg');
$raw="aabbcrdfghmnejaachtol";
foreach($word_array as $word=>$value)
{
$raw_array= str_split($raw);
$res[$value]='Yes';
$word_value= str_split($value);
foreach($word_value as $w=>$w_value)
{
if(!in_array($w_value,$raw_array))
{
$res[$value]='No';
}
else
{
unset($raw_array[array_search($w_value, $raw_array)]);
}
}
}
This will not allow character again, if it is used once Like "total".
We can check to see if each letter from each word is within the letters given, and pluck found letters out as we go.
The function below short circuits if a letter is not found.
<?php
function can_form_word_from_letters($word, $letters) {
$letters = str_split($letters);
$word_letters = str_split($word);
foreach($word_letters as $letter) {
$key = array_search($letter, $letters);
if($key === false) return;
unset($letters[$key]); // Letter found, now remove it from letters.
}
return true;
}
$letters = "aabbcdfghmnejaachto";
$words = array('cat','rat','goat','total','egg');
foreach($words as $word) {
$result[$word] = can_form_word_from_letters($word, $letters) ? 'Yes' : 'No';
}
var_dump($result);
Output:
array (size=5)
'cat' => string 'Yes' (length=3)
'rat' => string 'No' (length=2)
'goat' => string 'Yes' (length=3)
'total' => string 'No' (length=2)
'egg' => string 'No' (length=2)

Number permutations in PHP with repeated characters

I store a number in a string. My code shuffles the digits into different permutations.
Example if the input is:
'123'
then the output permutations will be:
123,132,213,231,321,312
If the input string has repeated digits, my code does not work, and goes into an infinite loop.
Example inputs that don't work:
11,22,33,44,55,455,998,855,111,555,888,222 etc.
My code:
<?php
function factorial($n){
if($n==1) return $n;
return $n*factorial($n-1);
}
$a = '1234';
$_a = str_split($a);
$num = count($_a);
$ele_amnt = factorial($num);
$output = array();
while(count($output) < $ele_amnt){
shuffle($_a);
$justnumber = implode('', $_a);
if(!in_array($justnumber , $output))
$output[] = $justnumber;
}
sort($output);
print_r($output);
Can anyone explain why and how to fix it?
Short version: Your terminating condition for the while loop "is" permutational while your if(!in_array...) test "is" combinational.
Let's assume $a=11;: then $ele_amnt is 2 and your while loop will stop when the array $output contains more than one element.
Your shuffle/implode code can produce either the string <firstelement><seconelement> or <secondelement><firstelement>, both being 11.
And if(!in_array( $justnumber , $output)) allows only one of them to be appended to $output. So count($output) will be 1 after the first iteration and will stay 1 in perpetuity. Same for every $a with duplicate digits.
shuffle() changes the position of elements in an array at random. SO, the performance of the algorithm depends on ....luck ;-)
You might be interested in something like https://pear.php.net/package/Math_Combinatorics instead.
Your output array will contain less permutations if you have repeated characters in your input. So your loop never completes.
You could map your inputs, then later map back from your output, and then filter to do as you desire:
// For a string '122' we get the permutations of '123' first and then process.
$output = op_code_no_repeats('123');
$filtered = array();
foreach($output as $permutation) {
$filtered[] = str_replace('3', '2', $permutation);
}
$filtered = array_unique($filtered);
var_dump($filtered);
Outputs:
array (size=3)
0 => string '122' (length=3)
2 => string '212' (length=3)
3 => string '221' (length=3)
Your code with guards on the factorial and permutation functions:
function factorial($n)
{
if(! is_int($n) || $n < 1)
throw new Exception('Input must be a positive integer.');
if($n==1)
return $n;
return $n * factorial($n-1);
};
function op_code_no_repeats($a) {
$_a = str_split($a);
if(array_unique($_a) !== $_a)
throw new Exception('Does not work for strings with repeated characters.');
$num = count($_a);
$perms_count = factorial($num);
$output = array();
while(count($output) < $perms_count){
shuffle($_a);
$justnumber = implode('', $_a);
if(!in_array($justnumber , $output))
$output[] = $justnumber;
}
sort($output);
return $output;
}

encode string in PHP as a=1,b=2 and so on

I want to create PHP function to encode any string just with following rule.
a=1; b=2; c=3;.....y=25;z=26;
for eg.
If my string is "abc" then my encoded data will be "123".
We can use $key=>$value array but it will iterate 26 times for every letter!!
Use some delimiter so that you can identify separate characters. You can try this.
$chars = array('a' => 1, 'b' => 2, 'c' => 3, 'd' => 4);
$str = "acd";
$encoded = array();
for ($i = 0; $i < strlen($str); $i++) {
$encoded[] = $chars[$str[$i]];
}
echo implode('|', $encoded);
Output
1|3|4
function encodedString($your_string)
$alpha_arr = range("A", "Z");
$your_string = strtoupper($your_string);
$encoded = "";
for($i=0; $i<strlen($your_string); $i++)
{
$strOne = substr($your_string, $i, 1);
if (in_array($strOne, $alpha_arr))
{
$encoded .= array_search($strOne, $alpha_arr)+1;
}
}
return $encoded;
}
You should have a padded encoding number to avoid confusions, with an array such as:
$converter = array('a' => '01', 'b' => '02' ...);
then go through each letter of the original string and construct your encoded string accessing the $converter array by key ('a', 'b' ... 'z').
you can also use str_replace to loop through the converter array and replace each character. Using str_replace you have at most N iterations, where N is the number of items in the converter array, regardless of the original string dimension.
The ord() method outputs the ascii value. now you can subtract 64 and 96 based on the text case to get the corresponding values. You will need no iterations or loop or anything. use a change case function and get the ascii value. the subtract the constant.
More details about ord method here

How to convert string that contains multiple json data in proper json format in php?

How can I convert this string:
{"id":"tag:search.twitter.com,2005:1"}{"id":"tag:search.twitter.com,2005:2"}
{"id":"tag:search.twitter.com,2005:3"}{"id":"tag:search.twitter.com,2005:4"}
Into this JSON format:
[
{"id":"tag:search.twitter.com,2005:1"},
{"id":"tag:search.twitter.com,2005:2"},
{"id":"tag:search.twitter.com,2005:3"},
{"id":"tag:search.twitter.com,2005:4"}
]
You can do it like this:
$str = '{"id":"tag:search.twitter.com,2005:1"}{"id":"tag:search.twitter.com,2005:2"}
{"id":"tag:search.twitter.com,2005:3"}{"id":"tag:search.twitter.com,2005:4"}';
// wrap the string in [] to make it an array (when decoded).
// replace all the '}<spaces/line breaks/tabs>{' to '},{' to make it valid JSON array.
// decode the new JSON string to an object.
$obj = json_decode('[' . preg_replace('/}\s*{/', '},{', $str) . ']');
var_dump($obj);
Output:
array (size=4)
0 =>
object(stdClass)[424]
public 'id' => string 'tag:search.twitter.com,2005:1' (length=29)
1 =>
object(stdClass)[517]
public 'id' => string 'tag:search.twitter.com,2005:2' (length=29)
2 =>
object(stdClass)[518]
public 'id' => string 'tag:search.twitter.com,2005:3' (length=29)
3 =>
object(stdClass)[519]
public 'id' => string 'tag:search.twitter.com,2005:4' (length=29)
Thanks for giving your comments on my question...I have resolved my issue by putting below code
foreach (preg_split("/((\r?\n)|(\r\n?))/", $tdata) as $line)
{
print_r(json_decode($line));
}
Assuming that your string is composed of valid JSON object put together without any delimiter, you can do the following:
Split the string with }{ as delimiter
Loop over each item in the resulting array and add the missing parts
Merge the array into one string with a , as delimiter
Add the JSON array marks before and after the string
Example (with $input as the input string):
$chunks = explode('}{', $input);
$n = count($chunks);
for($i = 0; $i < $n; $i++) {
if($i == 0) {
$chunks[$i] = $chunks[$i].'}';
} else if($i == $n - 1) {
$chunks[$i] = '{'.$chunks[$i];
} else {
$chunks[$i] = '{'.$chunks[$i].'}';
}
}
$output = '['.implode(',', $chunks).']';
Note that it will work on imbricated structures, but will miserably fail if you have a }{ in the text. But it is unlikely.
EDIT: One simple way of checking if the current chunk is a wrong cut could be by checking is the next chunk start with a ", because JSON object's attributes are always quoted. If not, then you can merge the current and next chunk and repeat until finding the right character.

How can I turn a list of items into a php array?

word 1
word 2
word 3
word 4
And so on... How can I turn that into a php array, here will be a lot of items so I don't want to write them all out into an array manually and I know there has to be a simple way
I mean do I have to do
<?PHP
$items = array();
$items['word 1'];
$items['word 2'];
$items['word 3'];
$items['word 4'];
?>
UPDATE got it thanks
<?php
$items = "word1 word2 word3 word4";
$items = explode(" ", $items);
echo $items[0]; // word1
echo $items[1]; // word2
?>
If you mean:
word1 word2 word3
Then you want
$array = explode(' ', "word1 word2 word3");
If you actually mean "word 1 word 2 word 3", with numbers inbetween, then you'll need to get a little fancier with preg_split()
if you have all your words in a text file, one per line
you can use the file function which will read the whole file into an array, one item per line
http://nz.php.net/manual/en/function.file.php
$items = array("word1","word2","word3","word4");
If I understand the question, you have a set of variables, like this :
$word1 = 'a';
$word2 = 'b';
$word3 = 'c';
$word4 = 'd';
$word5 = 'e';
$word6 = 'f';
$word7 = 'g';
$word8 = 'h';
If yes, you could use PHP's Variable variables, like this :
$list = array();
for ($i = 1 ; $i <= 8 ; $i++) {
$variable_name = 'word' . $i;
$list[] = $$variable_name;
}
var_dump($list);
And you'd get, as output :
array
0 => string 'a' (length=1)
1 => string 'b' (length=1)
2 => string 'c' (length=1)
3 => string 'd' (length=1)
4 => string 'e' (length=1)
5 => string 'f' (length=1)
6 => string 'g' (length=1)
7 => string 'h' (length=1)
If I didn't understand the question and you only have one string at first... You'll probably have to use explode to separate the words...
EDIT
(Well, I didn't understand the question, it seems... There were not as many examples given when I first answered -- sorry ^^)
I was working with the gallery shortcode in the wordpress and found the output was [212,232,34,45,456,56,78] something like this. The following code helped me to make array of the list and then deal with each attachment id.
$list = '212,232,34,45,456,56,78';
$tag_array = explode(',', $list );
foreach ($tag_array as $key => $tag ) {
// do something with each list item.
}

Categories