I am looking for the most efficient way to find the most common character in a php string.
I have a string that looks like this:
"aaaaabcaab"
The result should be stored in the variable $total.
So in this case $total should be equal to a
You can use this function,
function getHighest($str){
$str = str_replace(' ', '', $str);//Trims all the spaces in the string
$arr = str_split(count_chars($str.trim($str), 3));
$hStr = "";
$occ = 0;
foreach ($arr as $value) {
$oc = substr_count ($str, $value);
if($occ < $oc){
$hStr = $value;
$occ = $oc;
}
}
return $hStr;
}
Te easiest way to achieve this is:
// split the string per character and count the number of occurrences
$totals = array_count_values( str_split( 'fcaaaaabcaab' ) );
// sort the totals so that the most frequent letter is first
arsort( $totals );
// show which letter occurred the most frequently
echo array_keys( $totals )[0];
// output
a
One thing to consider is what happens in the event of a tie:
// split the string per character and count the number of occurrences
$totals = array_count_values( str_split( 'paabb' ) );
// sort the totals so that the most frequent letter is first
arsort( $totals );
// show all letters and their frequency
print_r( $totals );
// output
Array
(
[b] => 2
[a] => 2
[p] => 1
)
Related
I have SKU numbers imported from a CSV file into SQL DB.
Pattern look like:
55A_3
345W_1+04B_1
128T_2+167T_2+113T_8+115T_8
I am trying to move all the letters in front of the numbers.
like:
A55_3
W345_1+B04_1
T128_2+T167_2+T113_8+T115_8
My best idea how to do it was to search for 345W and so, and to replace it with W345 and so:
$sku = "345W_1+04B_1";
$B_range_num = range(0,400);
$B_range_let = range("A","Z");
then generating the find and replace arrays
$B_find =
$B_replace =
maybe just using str_replace??
$res = str_replace($B_find,$B_replace,$sku);
Result should be for all SKU numbers
W345_1+B04_1
Any ideas?
You can use preg_replace to do this job, looking for some digits, followed by a letters and one of an _ with digits, a + or end of string, and then swapping the order of the digits and letters:
$skus = array('55A_3',
'345W_1+04B_1',
'128T_2+167T_2+113T_8+115T_8',
'55A');
foreach ($skus as &$sku) {
$sku = preg_replace('/(\d+)([A-Z]+)(?=_\d+|\+|$)/', '$2$1', $sku);
}
print_r($skus);
Output:
Array
(
[0] => A55_3
[1] => W345_1+B04_1
[2] => T128_2+T167_2+T113_8+T115_8
[3] => A55
)
Demo on 3v4l.org
Here I defined a method with specific format with unlimited length.
$str = '128T_2+167T_2+113T_8+115T_8';
echo convertProductSku($str);
function convertProductSku($str) {
$arr = [];
$parts = explode('+', $str);
foreach ($parts as $part) {
list($first, $second) = array_pad(explode('_', $part), 2, null);
$letter = substr($first, -1);
$number = substr($first, 0, -1);
$arr[] = $letter . $number . ($second ? '_' . $second : '');
}
return implode('+', $arr);
}
So my question might not be the best, so sorry for that.
I have an array with strings and want to write a text with the help of another array using it as the order/key. This is the Input:
$words =["I","am","cool"];
$order =["2","0","1","0","1","2"];
//var_export($words);
// array (
// 0 => 'I',
// 1 => 'am',
// 2 => 'cool',
// )
I want to use $order as some sort of key to rearrange $words so I can get this Output:
"Cool I am I am cool"
Help is much appreciated, thank you :)
Use the values of $order as the keys for $words.
$words =["I","am","cool"];
$order =["2","0","1","0","1","2"];
$output = '';
foreach($order as $key) {
$output .= $words[$key] . ' ';
}
echo ucfirst(trim($output));
Demo: https://eval.in/780785
The empty($real_key) is to check if it is the first iteration. Also could be == 0.
I would recommend the use of array_map and join
There is no need for
side-effecting manual iteration using foreach
if statements or ternary (?:) expressions
variable reassignment
string concatenation using .
checking array lengths
Here we go
function map_indexes_to_words ($indexes, $words) {
$lookup = function ($i) use ($words) {
return $words[(int) $i];
};
return join(' ', array_map($lookup, $indexes));
}
$words = ["I","am","cool"];
$order = ["2","0","1","0","1","2"];
echo map_indexes_to_words($order, $words);
// 'cool I am I am cool'
Start with an empty array.
Then loop through the order array and add the word array part to the new string.
$my_string= array();
foreach ( $order as $index ) {
$index = int($index);
$my_string[] = ( isset($words[ $index]) ) ? $words[ $index ] : '' );
}
$my_string = implode(' ', $my_string);
echo my_string;
Iterate over order and use it's values as keys to words; Convert the following code to php it should be pretty simple...
foreach (string orderIndexString in order) {
int orderIndexInt = System.Convert.ToInt16(orderIndexString); // convert string to int
if(orderIndexInt < 0 || orderIndexInt >= words.Length)
continue;
print (words[orderIndexInt]); // either print or add it to another string
}
I have a string and a value.
I am exploding the string which returns a few results to a list.
I want to add each of those items from the list to an array, with the same value assigned to each string.
Here is what I have so far:
$count = 3;
$amount = 2500;
$value = ceil ($amount / $count);
$string = "String1, String2, String3, ";
$strings = explode(", ", $string);
I want to run a foreach that puts $strings and $value into an array together.
Any pointers?
You can simply use:
$combo = array_fill_keys( $strings , $value );
// var_dump( $combo ); // to check you got it right.
This takes the values in your $strings array and uses them as the keys for the new $combo array, setting the same value for each key.
I am quite a newbie when it comes to php and i wanted to try something but i have absolutely no idea how should i do this.. To be honest i am not sure if can explain this to you very clearly either.. Lets get started..
I have couple of letters for example a, b, c, d and e..
and for each one of them i have couples of two-charactered values like this:
a -> fg, dz, gc, bg
b -> zt, hg, oq, vg, gb
c -> lt, pr, cs, sh, pr
d -> kt, nt, as, pr
e -> zd, ke, cg, sq, mo, ld
Here comes the question:
I would like to get a random value for each time for example: dcbae
and for this the ultimate output should be something like this: ntshztdzld or asltvggcmo..
(After generating a random string with the charachters above (between a-e), i should generate another string that contains random values those are related with the each character..
This is not a homework or something similar.
Thanks in advance for your understanding..
Well, you would first create a map:
$map = Array(
"a" => Array("fg","dz","gc","bg"),
"b" => Array("zt","hg","oq","vg","gb"),
"c" => Array("lt","pr","cs","sh","pr"),
"d" => Array("kt","nt","as","pr"),
"e" => Array("zd","ke","cg","sq","mo","ld")
);
I notice that you have the same pair "pr" several times - if you want this encoding to be reversible, avoid duplicates.
Anyway, once you have that it's easy enough to loop through your input string and get a random output:
$input = "dcbae";
$len = strlen($input);
$output = "";
for( $i=0; $i<$len; $i++) {
$entry = &$map[$input[$i]];
if( isset($entry)) $output .= $entry[mt_rand(0,count($entry)-1)];
else $output .= "??";
}
$output is the result.
<?php
// Setup matching values
$encpairs[ 'a' ] = array( 'fg', 'dz', 'gc', 'bg' );
$encpairs[ 'b' ] = array( 'zt', 'hg', 'oq', 'vg', 'gb' );
$encpairs[ 'c' ] = array( 'lt', 'pr', 'cs', 'sh', 'pr' );
// etc. etc.
// Define input string
$my_string = 'abc';
// To randomly build input string
$my_string = '';
$last_key = '';
$key = '';
$keys = array_keys( $encpairs );
$ttl_keys = count( $keys ) -1;
// Generate the input string at random; change "5" to length you desire
for ( $j=0; $j < 5; $j++ ){
// Randomly select a key from $encpairs array (giving you one letter at random)
// The while loop ensures no two letters are used consecutively
while ( $key == $last_key ) {
$key =$keys[ rand(0, $ttl_keys ) ];
}
$last_key = $key;
$my_string .= $key;
}
// Determine input string length
$length = strlen( $my_string );
// Loop through each letter
$output = '';
for( $i=0; $i < $length; $i++ ){
shuffle( $encpairs[ $my_string[$i] ] );
$output.= $encpairs[ $my_string[$i] ][0]; // Added [0]
}
Start by initializing a second string outside of the loop. Convert your original string (to be encrypted) into an array, and then loop through the whole array and append to the second string.
So you get
$splitstr=str_split($original);
$final_string="";
$map=Array(/**/);
foreach($splitstr as $char)
{
$final_string.=$map[$char][rand(0,count($map[$char])-1)];
}
return $final_string;
I have a set of strings, each string has a variable number of segments separated by pipes (|), e.g.:
$string = 'abc|b|ac';
Each segment with more than one char should be expanded into all the possible one char combinations, for 3 segments the following "algorithm" works wonderfully:
$result = array();
$string = explode('|', 'abc|b|ac');
foreach (str_split($string[0]) as $i)
{
foreach (str_split($string[1]) as $j)
{
foreach (str_split($string[2]) as $k)
{
$result[] = implode('|', array($i, $j, $k)); // more...
}
}
}
print_r($result);
Output:
$result = array('a|b|a', 'a|b|c', 'b|b|a', 'b|b|c', 'c|b|a', 'c|b|c');
Obviously, for more than 3 segments the code starts to get extremely messy, since I need to add (and check) more and more inner loops. I tried coming up with a dynamic solution but I can't figure out how to generate the correct combination for all the segments (individually and as a whole). I also looked at some combinatorics source code but I'm unable to combine the different combinations of my segments.
I appreciate if anyone can point me in the right direction.
Recursion to the rescue (you might need to tweak a bit to cover edge cases, but it works):
function explodinator($str) {
$segments = explode('|', $str);
$pieces = array_map('str_split', $segments);
return e_helper($pieces);
}
function e_helper($pieces) {
if (count($pieces) == 1)
return $pieces[0];
$first = array_shift($pieces);
$subs = e_helper($pieces);
foreach($first as $char) {
foreach ($subs as $sub) {
$result[] = $char . '|' . $sub;
}
}
return $result;
}
print_r(explodinator('abc|b|ac'));
Outputs:
Array
(
[0] => a|b|a
[1] => a|b|c
[2] => b|b|a
[3] => b|b|c
[4] => c|b|a
[5] => c|b|c
)
As seen on ideone.
This looks like a job for recursive programming! :P
I first looked at this and thought it was going to be a on-liner (and probably is in perl).
There are other non-recursive ways (enumerate all combinations of indexes into segments then loop through, for example) but I think this is more interesting, and probably 'better'.
$str = explode('|', 'abc|b|ac');
$strlen = count( $str );
$results = array();
function splitAndForeach( $bchar , $oldindex, $tempthread) {
global $strlen, $str, $results;
$temp = $tempthread;
$newindex = $oldindex + 1;
if ( $bchar != '') { array_push($temp, $bchar ); }
if ( $newindex <= $strlen ){
print "starting foreach loop on string '".$str[$newindex-1]."' \n";
foreach(str_split( $str[$newindex - 1] ) as $c) {
print "Going into next depth ($newindex) of recursion on char $c \n";
splitAndForeach( $c , $newindex, $temp);
}
} else {
$found = implode('|', $temp);
print "Array length (max recursion depth) reached, result: $found \n";
array_push( $results, $found );
$temp = $tempthread;
$index = 0;
print "***************** Reset index to 0 *****************\n\n";
}
}
splitAndForeach('', 0, array() );
print "your results: \n";
print_r($results);
You could have two arrays: the alternatives and a current counter.
$alternatives = array(array('a', 'b', 'c'), array('b'), array('a', 'c'));
$counter = array(0, 0, 0);
Then, in a loop, you increment the "last digit" of the counter, and if that is equal to the number of alternatives for that position, you reset that "digit" to zero and increment the "digit" left to it. This works just like counting with decimal numbers.
The string for each step is built by concatenating the $alternatives[$i][$counter[$i]] for each digit.
You are finished when the "first digit" becomes as large as the number of alternatives for that digit.
Example: for the above variables, the counter would get the following values in the steps:
0,0,0
0,0,1
1,0,0 (overflow in the last two digit)
1,0,1
2,0,0 (overflow in the last two digits)
2,0,1
3,0,0 (finished, since the first "digit" has only 3 alternatives)