I would like to Convert simple string to another format based on below logic
Example 1 : if string is 3,4-8-7,5 then I need the set as (3,8,7),(4,8,5).
Example 2: If string is "4-5,6-4" then required set will be (4,5,4),(4,6,4).
More Clear Requirements:
if string is 5-6,7,8-2,3-1. It need to be divided first like [5] AND [(6) OR (7) OR (8)] AND [(2) OR (3)] AND [1]. Result must be All possible combination: (5,6,2,1),(5,6,3,1),(5,7,2,1),(5,7,3,1),(5,8,2,1),(5,8,3,1).
The Logic behind to building the set are we need to consider ',' as OR condition and '-' as AND condition.
I am trying my best using For loop but unable to find solution
$intermediate = array();
$arry_A = explode('-', '3,4-8-7,5');
for ($i = 0; $i < count($arry_A); $i++) {
$arry_B = explode(',', $arry_A[$i]);
for ($j = 0; $j < count($arry_B); $j++) {
if (count($intermediate) > 0) {
for ($k = 0; $k < count($intermediate); $k++) {
$intermediate[$k] = $intermediate[$k] . ',' . $arry_B[$j];
}
} elseif (count($intermediate) === 0) {
$intermediate[0] = $arry_B[$j];
}
}
}
echo $intermediate, should give final result.
Cool little exercise!
I would do it with the following code, which I will split up for readability:
I used an array as output, since it's easier to check than a string.
First, we initialize the $string and create the output array $solutions. We will calculate the maximum of possible combinations from the beginning ($results) and fill the $solutions array with empty arrays which will be filled later with the actual combinations.
$string = '3,4-8-7,5';
$solutions = array();
$results = substr_count($string,',')*2;
for($i = 0; $i < $results; $i++) {
array_push($solutions,array());
}
We will need two helper functions: checkSolutions which makes sure, that the combination does not yet exist more than $limit times. And numberOfORAfterwards which will calculate the position of an OR pattern in the $string so we can calculate how often a combination is allowed in the single steps of the walkthrough.
function checkSolutions($array,$solutions,$limit) {
$count = 0;
foreach($solutions as $solution) {
if($solution === $array) $count++;
}
if($count < $limit) return true;
else return false;
}
function numberOfORAfterwards($part,$parts) {
foreach($parts as $currPart) {
if($currPart === $part) $count = 0;
if(isset($count)) if(!ctype_digit($currPart)) $count++;
}
return $count;
}
Now the main part: We are going to loop over the "parts" of the $string a part are the digits between AND operations.
If you need further explanation on this loop, just leave a comment.
$length = 0;
// split by all AND operations
$parts = explode('-',$string);
foreach($parts as $part) {
if(ctype_digit($part)) {
// case AND x AND
foreach($solutions as &$solution) {
array_push($solution,$part);
}
} else {
// case x OR x ...
$digits = explode(',',$part);
foreach($digits as $digit) {
for($i = 0; $i < $results/count($digits); $i++) {
foreach($solutions as &$solution) {
if(count($solution) == $length) {
$test = $solution;
array_push($test,$digit);
$limit = numberOfORAfterwards($part,$parts);
echo $digit.' '.$limit.'<br>';
if(checkSolutions($test,$solutions,$limit)) {
array_push($solution,$digit);
break;
}
}
}
}
}
}
$length++;
}
print_r($solutions);
Some tests:
String: 3,4-8-7,5
Combinations: (3,8,7)(3,8,5)(4,8,7)(4,8,7)
String: 5-6,7,8-2,3-1
Combinations: (5,6,2,1)(5,6,3,1)(5,7,2,1)(5,7,3,1)(5,8,2,1)(5,8,2,1)
String: 2,1-4-3,2-7,8-9
Combinations: (2,4,3,7,9)(2,4,3,8,9)(2,4,2,7,9)(1,4,3,7,9)(1,4,2,8,9)(1,4,2,8,9)
String: 1,5-3,2-1
Combinations: (1,3,1)(1,2,1)(5,3,1)(5,3,1)
Related
Hello there i am making a program which will let me help generate a random string with a specified limit and random strings of *&# but then the combination of *&# should not repeat.
Ex: if I input 3 then the O/P should be
#**
**#
**#
It should generate a random string of length 3 up to 3 rows with different patterns also the pattern should not repeat. I am using the below code but not able to attain it.
$n = 3;
for($i = 0; $i < n; $i++)
{
for($j=0;$j<=$n;j++)
{
echo "*#";
}
echo "<br />";
}
But I am not able to generate the output, where is my logic failing?
If you want to make sure the same pattern doesn't show up more than once you'll have to keep a record of the generated strings. In the most basic form it could look like this:
public function generate() {
$amount = 3; // The amount of strings you want.
$generated_strings = []; // Keep a record of the generated strings.
do {
$random = $this->generateRandomString(); // Generate a random string
if(!in_array($random, $generated_strings)) { // Keep the record if its not already present.
$generated_strings[] = $random;
}
} while(sizeof($generated_strings) !== $amount); // Repeat this process until you have three strings.
print_r($generated_strings);
}
public function generateRandomString($length = 3) {
$characters = '*&#';
$charactersLength = strlen($characters);
$randomString = '';
for ($i = 0; $i < $length; $i++) {
$randomString .= $characters[rand(0, $charactersLength - 1)];
}
return $randomString;
}
Not necessarily the most optimized algorithm but it should work.
I am using a string generator, somewhat random, combining the chars you have provided. The second part is filling the output array with generated strings that are not already present.
<?php
function randomize($n) {
$s = '';
for ($i = 0; $i < $n; $i++) {
$s. = (rand(0, 10) < 5 ? '*' : '#');
}
return $s;
}
$n = 3;
$output = array();
for ($i = 0; $i < $n; $i++) {
$tmp = randomize($n);
while (in_array($tmp, $output)) {
$tmp = randomize($n);
}
$output[] = $tmp;
}
print_r($output);
Visible here
You can use a while loop and array unique to do this.
I first have an array with possible chars.
Then I loop until result array is desired lenght.
I use array unique to remove any duplicates inside the loop.
I use rand(0,2) to "select" a random character from possible characters array.
$arr = ["*", "&", "#"];
$res = array();
$n =7;
While(count($res) != $n){
$temp="";
For($i=0;$i<$n;$i++){
$temp .= $arr[Rand(0,count($arr)-1)];
}
$res[] = $temp;
$res = array_unique($res);
}
Var_dump($res);
https://3v4l.org/Ko4Wd
Updated with out of scope details not clearly specified by OP.
I need help to create a licence plate (6 character length) from different equal or unequal length of strings.
Example 1:
$str1 = "YE37";
$str2 = "TE37";
$str3 = "LYTE";
When I combine, it should give me "LYTE37". I must use all of them to formulate a plate. I can find the common longest sequence between $str1 and $str2 is "E37" but unsure "Y" or "T" comes first (i.e., whether "YTE37" or "TYE37")" then I can combine with $str3 using the longest common sequence ("YTE") which supposed to give me "LYTE37".
Example 2: "YLF3", "EYLF" and "YLF37" should give me "EYLF37".
I use the following function that finds the longest common sequence
$string_1="YE37";
$string_2="TE37";
$S =get_longest_common_subsequence($string_1, $string_2); // $S is "E37"
function get_longest_common_subsequence($string_1, $string_2)
{
$string_1_length = strlen($string_1);
$string_2_length = strlen($string_2);
$return = '';
if ($string_1_length === 0 || $string_2_length === 0)
{
// No similarities
return $return;
}
$longest_common_subsequence = array();
// Initialize the CSL array to assume there are no similarities
$longest_common_subsequence = array_fill(0, $string_1_length, array_fill(0, $string_2_length, 0));
$largest_size = 0;
for ($i = 0; $i < $string_1_length; $i++)
{
for ($j = 0; $j < $string_2_length; $j++)
{
// Check every combination of characters
if ($string_1[$i] === $string_2[$j])
{
// These are the same in both strings
if ($i === 0 || $j === 0)
{
// It's the first character, so it's clearly only 1 character long
$longest_common_subsequence[$i][$j] = 1;
}
else
{
// It's one character longer than the string from the previous character
$longest_common_subsequence[$i][$j] = $longest_common_subsequence[$i - 1][$j - 1] + 1;
}
if ($longest_common_subsequence[$i][$j] > $largest_size)
{
// Remember this as the largest
$largest_size = $longest_common_subsequence[$i][$j];
// Wipe any previous results
$return = '';
// And then fall through to remember this new value
}
if ($longest_common_subsequence[$i][$j] === $largest_size)
{
// Remember the largest string(s)
$return = substr($string_1, $i - $largest_size + 1, $largest_size);
}
}
// Else, $CSL should be set to 0, which it was already initialized to
}
}
// Return the list of matches
return $return;
}
I need an algorithm that uses these strings and creates a licence plate.
Could this be the Algorithm you are looking for? Quick-Test Here.
<?php
$str1 = "YE37";
$str2 = "TE37";
$str3 = "LYTE";
$strA = "YLF3";
$strB = "EYLF";
$strC = "YLF37";
function generatePlateNumber($str1, $str2, $str3) {
$plateNumber = '';
$arr = array($str1, $str2, $str3);
$arrStr = array();
foreach($arr as $str){
if(!preg_match("#\d#", $str)){
$arrStr[] = $str;
}
}
foreach($arr as $str){
if(preg_match("#\d#", $str)){
$arrStr[] = $str;
}
}
$chars = array_merge(str_split($arrStr[0]),
str_split($arrStr[1]),
str_split($arrStr[2]) );
$alphabets = [];
$numbers = [];
foreach($chars as $char){
if(is_numeric($char)){
$numbers[] = $char;
}else{
$alphabets[] = $char;
}
}
$alphabets = array_unique($alphabets);
$numbers = array_unique($numbers);
// BUILD THE PLATE NUMBER:
$plateNumber .= implode($alphabets) . implode($numbers);
return $plateNumber;
}
This is a function I wrote for a Radix Sort in PHP.
It works for all cases where the array is populated with numbers greater than 0.
function radix_sort($arr) {
// Find the number of passes needed to complete the sort
$passes = strlen((string)max($arr));
$buckets = [];
// Start the passes
for($i = 1; $i <= $passes; $i++) {
// Create - reinitialize some buckets
for ($b = 0; $b <= 9; $b++) {
$buckets[$b] = [];
}
for ($j = 0; $j < count($arr); $j++) {
// Drop into the proper bucket based on the significant digit
$numStr = (string)$arr[$j];
if (strlen($numStr) < $i) {
$bucketsIndex = 0;
} else {
$bucketsIndex = $numStr[strlen($numStr) - $i];
}
array_push($buckets[$bucketsIndex], $arr[$j]);
}
// Repopulate our array by pulling out of our buckets
$k = 0;
foreach ($buckets as $bucket) {
foreach ($bucket as $value) {
$arr[$k] = $value;
$k++;
}
}
}
return $arr;
}
I feel like there's too much type converting going on. Is it ok to be doing this? If I wanted to pull the Nth digit from a large number, is there a better way in PHP?
You could convert all the value to string before the function, and then revert back to int at the end:
function radix_sort($arr) {
$arr = array_map ('strval', $arr) ;
$passes = strlen(max($arr)) ; // Should still work since all values are numeric
/* Do your stuff... */
return array_map ('intval', $arr) ;
}
Then in your inner loop you could store the length (I don't really know the complexity of strlen in PHP but I assumed it is not O(1)):
for ($j = 0; $j < count($arr); $j++) {
// Drop into the proper bucket based on the significant digit
$numStr = $arr[$j];
$numLen = strlen($numStr) ;
if ($numLen < $i) {
$bucketsIndex = 0;
} else {
$bucketsIndex = $numStr[$numLen - $i];
}
array_push($buckets[$bucketsIndex], $arr[$j]);
}
Or you could even (if you have enough memory) use an array to precompute the length:
$lengths = array_map ('strlen', $arr) ;
I have an array:
$arr=array("A","B","C");
I want to make its all of combination as:
array("A")
array("B")
array("C")
array("A","B")
array("A","C")
array("B","C")
array("A","B","C")
i want to make an process all of this combinations but i don't want generate all combinations, store them in an array and apply function to them. Because this requires a lot of memory with large combinations. I have 40 items for this process (I have long time but i don't have enough memory).
I want to have a function like this:
function ProcessArrayCombinations($array){
foreach($array as $v){
//generate and process next combination of array
print_r($nextcombination);
}
}
Thank you.
This code recognizes the combinations as binary numbers, using the fact that there is a formula which states that the sum of all combinations possible from n elements is 2^n. Knowing its binary logarithm is integer, we can define a model where each possible binary number constructed from n digits is a set of combinations. Code is untested, if there are typos, please, let me know in comments.
function ProcessArrayCombinations($array) {
$status = array();
foreach ($array as $element) {
$status[] = false;
}
$elementCount = count($status);
$trues = 0;
while ($trues < $elementCount) {
$index = 0;
$stop = false;
while ((!$stop) && ($index < count($status)) && ($status[$index])) {
$status[$index] = false;
$trues--;
$index++;
}
$status[$index] = true;
$trues++;
//Found a new combination
//We should print elements from $array located at indexes fulfilling
//the criteria that the element having the same index in $status is true:
//for ($i = 0; $i < count($status); $i++) {
// if ($status[$i}) {
// print
// } else {
// don't print
// }
//}
}
}
I edited and used your function as below. Thank you again Lajos.
function ProcessArrayCombinations($array) {
$status = array();
foreach ($array as $element) {
$status[] = false;
}
$elementCount = count($status);
$trues = 0;
while ($trues < $elementCount) {
$index = 0;
$stop = false;
while ((!$stop) && ($index < count($status)) && ($status[$index])) {
$status[$index] = false;
$trues--;
$index++;
}
$status[$index] = true;
$trues++;
//Found a new combination
//We should print elements from $array located at indexes fulfilling
//the criteria that the element having the same index in $status is true:
for ($i = 0; $i < count($status); $i++) {
if ($status[$i]) {
echo $array[$i];
}
}
echo '<br/>';
}
}
I have an issue to deal with here (a logical error in my code 99%). I just can't seem to find the way to fix it, but I bet one of you will find the problem in no time!
I have to create a function which sorts array passed to it in asc or desc order, but can't use any array sorting functions !
I've been struggling with loops until now and I finally want to ask help from other devs ( you ).
Currently only code for ascending is worked on, descending will be no problem I assume once I do this one. It kinda of does sort values up to some point, but then stops ( it stops if the next smallest value is at the end of the passed array ). What could I do to prevent this and make it sort the whole array and it's elements?
Here is the code so far.
<?php
function order_array($array,$mode = 'ascending') {
$length = count($array);
if($mode == 'descending') {
return $array;
} else {
$sorted_array = array();
$used_indexes = array();
for($i = 0; $i < $length; $i++) {
$smallest = true;
echo $array[$i] . '<br/>';
for($y = 0; $y < $length; $y++) {
//echo $array[$i] . ' > ' . $array[$y] . '<br/>';
// if at ANY time during checking element vs other ones in his array, he is BIGGER than that element
// set smallest to false
if(!in_array($y,$used_indexes)) {
if($array[$i] > $array[$y]) {
$smallest = false;
break;
}
}
}
if($smallest) {
$sorted_array[] = $array[$i];
$used_indexes[] = $i;
}
}
return $sorted_array;
}
}
$array_to_sort = array(1, 3, 100, 99, 33, 20);
$sorted_array = order_array($array_to_sort);
print_r($sorted_array);
?>
I've solved the issue myself by doing it completely different. Now it sorts correctly all the elements of the passed in array. The logical issue I had was of using for() loop. The for() loop ran only a set ( length of passed array ) number of times, while we need it to loop more than that, because we will need to loop all the way untill we have a new sorted array in ascending order. Here is the code that will work
function order_array($array,$mode = 'ascending') {
if($mode == 'descending') {
// for() wont work here, since it will only loop an array length of times, when we would need it
// to loop more than that.
while(count($array)){
$value = MAX($array);
$key = array_search($value, $array);
if ($key !== false) {
unset($array[$key]);
}
$sorted[] = $value;
}
return $sorted;
} else {
// for() wont work here, since it will only loop an array length of times, when we would need it
// to loop more than that.
while(count($array)){
$value = MIN($array);
$key = array_search($value, $array);
if ($key !== false) {
unset($array[$key]);
}
$sorted[] = $value;
}
return $sorted;
}
}
function order_array($array,$mode = 'ascending') {
$length = count($array);
$sorted_array = array();
$used_indexes = array();
for($i = 0; $i < $length; $i++) {
$smallest = true;
echo $array[$i] . '<br/>';
for($y = 0; $y < $length; $y++) {
//echo $array[$i] . ' > ' . $array[$y] . '<br/>';
// if at ANY time during checking element vs other ones in his array, he is BIGGER than that element
// set smallest to false
if(!in_array($y,$used_indexes)) {
if($array[$i] > $array[$y]) {
$smallest = false;
break;
}
}
}
if($smallest) {
$sorted_array[] = $array[$i];
$used_indexes[] = $i;
}
if($mode == 'descending') {
return array_reverse($sorted_array);
}
return $sorted_array;
}
}