Reduce n-digit number to its lowest possible value - php

This seems trivial but I'm baffled that I haven't been able to come to a solution on this. What I'm trying to do is:
Input -> 14025
Output -> 10245
Input -> 171
Output -> 117
And so on...

$input = 140205;
$temp = str_split($input);
sort($temp);
// find the 1st non-zero digit
$f = current(array_filter($temp));
// remove it from the array
unset($temp[array_search($f, $temp)]);
echo $output = $f . join($temp); // 100245
demo

A bit more verbose, but similar to previous answer
function smallestNumberFromDigits($string) {
//split string to digits
$array = str_split($string);
//sort the digits
sort($array);
//find the first digit larger than 0 and place it to the begining of array
foreach($array as $i => $digit) {
if($digit > 0) {
$tmp = $array[0];
$array[0] = $digit;
$array[$i] = $tmp;
break;
}
}
//return the imploded string back
return implode("", $array);
}

Related

How to concatenate strings without partial duplication in PHP?

I have a series of strings in PHP array.
Each string sometimes overlaps with the previous one (by one or more words) and sometimes doesn't overlap:
$My_Array = [
'The quick',
'quick brown',
'quick brown fox',
'jumps over the',
'over the',
'lazy dog',
];
I'd like to merge only those strings which have overlaps.
ie. where the characters at the start of one string already exist at the end of the preceding string.
My aim is to return the following array:
$My_Processed_Array = [
'The quick brown fox',
'jumps over the',
'lazy dog',
];
Work Completed so far:
I have put this together, which works in this instance, but I'm sceptical that it will cover all cases:
function process_my_array($array) {
for ($i = (count($array) - 1); $i > 0; $i--) {
// TURN STRING ELEMENTS INTO MINI-ARRAYS
$Current_Element = explode(' ', trim($array[$i]));
$Previous_Element = explode(' ', trim($array[($i - 1)]));
$End_Loop = FALSE;
// STRING-MATCHING ROUTINE
while ($End_Loop === FALSE) {
if ($Current_Element[0] === $Previous_Element[(count($Previous_Element) - 1)]) {
array_shift($Current_Element);
$array[$i] = implode(' ', $Current_Element);
$array[($i - 1)] .= ' '.$array[$i];
unset($array[$i]);
$array = array_values($array);
$End_Loop = TRUE;
}
elseif (count($Current_Element) > 1) {
$Current_Element[0] .= ' '.$Current_Element[1];
unset($Current_Element[1]);
$Current_Element = array_values($Current_Element);
if (isset($Previous_Element[(count($Previous_Element) - 2)])) {
$Previous_Element[(count($Previous_Element) - 2)] .= ' '.$Previous_Element[(count($Previous_Element) - 1)];
unset($Previous_Element[(count($Previous_Element) - 1)]);
$Previous_Element = array_values($Previous_Element);
}
}
elseif (count($Current_Element) === 1) {
$End_Loop = TRUE;
}
}
}
return $array;
}
More importantly, I'm almost certain there must be a much simpler way to achieve the target outcome than what I've put together above.
Split each string by space using explode().
Compare it with previous exploded string one by one.
Create a new pointer for comparison.
If the current pointer of current word doesn't match with current word in prev, reset pointer to 0. Else, keep incrementing current pointer.
This way, we got a hang of longest suffix in the previous string that is a prefix in the current string.
Slice out the exploded array from current pointer.
To stitch the residue of current string with the previous one, use array_merge and implode them back in the end.
If the current pointer happens to be 0 even after comparison, you can safely assume it is a completely new word.
Snippet:
<?php
$My_Processed_Array = [];
$prev = [];
$curr = [];
foreach($My_Array as $val){
$val = explode(" ",$val);
$ptr = 0;
foreach($prev as $index => $prev_val){
if($prev_val == $val[$ptr]){
$ptr++;
}else{
$ptr = 0;
}
if($ptr == count($val)){
if($index == count($prev) - 1) break;
$ptr = 0;
}
}
$sliced_data = array_slice($val, $ptr);
if($ptr == 0 && !empty($curr)){
$My_Processed_Array[] = implode(" " ,$curr);
$curr = [];
}
$curr = array_merge($curr,$sliced_data);
$prev = $val;
}
if(!empty($curr)){
$My_Processed_Array[] = implode(" " ,$curr);
}

Random Combination of r from set of integers 'n' without repetition

I want to group of integers (r) randomly from set of integers (n). For example n = 1,2,3,4,5,6 and r = 3, I want the output as {1,2,3} {4,5,6} so-on... but if 1 is used in one group i don't want it other group.. so-on. I want one unique combination as output. How can i do this in PHP ??
This code gives all combination without randomness
// view the real output
header('Content-Type: text/plain');
// your string
$letters = 'RAT';
// convert to array
$letters_array = array("RAT1 ", "RAT2 ", "RAT3 ", "RAT4 ", "RAT5 ","RAT6 ", "RAT7", "RAT8", "RAT9", "RAT10");
echo 'The number of two charcter combinations from that string is '.count($result = get_combos($letters_array, 3))."\n\n";
echo 'The following is the combinations array'."\n\n";
print_r(array_2d_to_1d($result));
function get_combos($input, $combo_length)
{
$input = array_values($input);
$code = '';
$cnt = count($input);
$ret = array();
$i0 = -1;
for($i=0;$i<$combo_length;++$i)
{
$k = 'i'.($i+1);
$code .= 'for($'.$k.'=$i'.$i.'+1; $'.$k.'< $cnt-'.($combo_length-$i-1).'; ++$'.$k.') ';
}
$code .= '$ret[] = array($input[$i'.implode('], $input[$i',range(1,$combo_length)).']);';
eval($code);
return $ret;
}
function str_2_array($input)
{
for($i = 0, $len = strlen($input); $i < $len; $i++)
{
$rtn[] = $input[$i];
}
return $rtn;
}
function array_2d_to_1d($input)
{
foreach($input as $key => $value)
{
$rtn[$key] = implode($value);
}
return $rtn;
}
I'm not a PHP guy so there will be no code here. But as for algorithm I think what you need is:
Optionally strip non-unique values from the source array
Perform random shuffle of the array
Slice the shuffled array into sub-arrays of required length.

php need assistance with regular expression

I want to parse and expand the given strings in PHP.
From
0605052&&-5&-7&-8
0605052&&-4&-7
0605050&&-2&-4&-6&-8
To
0605052, 0605053 ,0605054 ,0605055, 0605057, 0605058
0605052,0605053,0605054,0605057
0605050,0605051,0605052,0605054,0605056,0605058
can someone help me with that? thanks in advance!
Your question is not very clear, but I think you mean a solution like this:
Edited: Now the hole ranges were shown and not only the specified numbers.
<?php
$string = "0605052&&-5&-7&-8";
$test = '/^([0-9]+)\&+/';
preg_match($test, $string, $res);
if (isset($res[1]))
{
$nr = $res[1];
$test = '/\&\-([0-9])/';
preg_match_all($test, $string, $res);
$result[] = $nr;
$nrPart = substr($nr, 0, -1);
$firstPart = substr($nr, -1);
if (isset($res[1]))
{
foreach ($res[1] as &$value)
{
if ($firstPart !== false)
{
for ($i=$firstPart+1; $i<=$value; $i++)
{
$nr = $nrPart . $i;
$result[] = $nr;
}
$firstPart = false;
}
else
{
$nr = $nrPart . $value;
$result[] = $nr;
$firstPart = $value;
}
}
}
var_dump($result);
}
?>
This delivers:
result[0] = "0605052"
result[1] = "0605053"
result[2] = "0605054"
result[3] = "0605055"
result[4] = "0605057"
result[5] = "0605058"
I think a multi step approach is the best thing to do here.
E.g. take this as an example 0605052&&-5&-7&-8:
Split at -. The result will be 0605052&&, 5&, 7&, 8
The first result 0605052&& will help you create your base. Simply substring the numbers by finding first occurence of & and substring to the next to last number. Result will be 060505. You will also need the last number, so get it as well (which is 2 in this case).
Get the remaining ends now, all \d& are simple to get, simply take the first character of the string (or if those can be more than one number, use substring with first occurence of & approach again).
The last number is simple: it is 8.
Now you got all important values. You can generate your result:
The last number from 2., all numbers from 3. and the number from 4. together with your base are the first part. In addition, you need to generate all numbers from the last number of 2. and the first result of 3. in a loop by a step of 1 and append it to your base.
Example Code:
<?php
$str = '0605052&&-5&-7&-8';
$split = explode('-', $str);
$firstAmpBase = strpos($split[0], '&');
$base = substr($split[0], 0, $firstAmpBase - 1);
$firstEnd = substr($split[0], $firstAmpBase - 1, 1);
$ends = [];
$firstSingleNumber = substr($split[1], 0, strpos($split[1], '&'));
for ($i = $firstEnd; $i < $firstSingleNumber; $i++) {
array_push($ends, $i);
}
array_push($ends, $firstSingleNumber);
for ($i = 2; $i < count($split) - 1; $i++) {
array_push($ends, substr($split[$i], 0, strpos($split[$i], '&')));
}
array_push($ends, $split[count($split) - 1]);
foreach ($ends as $end) {
echo $base . $end . '<br>';
}
?>
Output:
0605052
0605053
0605054
0605055
0605057
0605058

Getting Undefined:Offset error messages with Sorting Algorithm

So I'm getting a lot of these errors when I run this code. I'm about to give up and just use the sorting functions baked into PHP. But I would love if anyone could see the problem here. Please see below code. Sorry in advance if it's hard to read.
The array input is fine as print_r outputs exactly as expected, but the actual sorting algorithm just won't work, no matter what I try. The two commented functions at the bottom were used in different trials.
<?php
//this function will pull a string from a txt file and pass characters to an array
function strToArray($file){
if ($handle = fopen($file, 'r')){
$string = fread($handle, filesize($file));
fclose($handle);
}
$strArray = str_split(preg_replace('/\s+/', '', $string)); //regex in preg_replace gets rid of all whitespaces; str_split converts string to array
$arrLen = array_count_values($strArray);
return $arrLen;
}
$arrayWithVal = strToArray("filetest.txt"); //intermediary to pass into next function
print_r($arrayWithVal); //see what I have so far
echo "<hr />";
$newArray = $arrayWithVal;
for ($i = 1; $i < count($newArray); $i++){
for ($j = $i-1; $j >= 0; $j--){
if ($newArray[$j] > $newArray[$j+1]){ //if value on left is bigger than current value
$oldValue = $newArray[$j+1];
$newArray[$j+1] = $newArray[$j];
$newArray[$j] = $oldValue;
//return $newArray;
}
else {
break; //if value on left is smaller, skip to next position
}
}
}
print_r($newArray); //END
/*
function insertionSort($array){
$newArray=$arrayWithVal;
for($j=1; $j < count($newArray); $j++){
$temp = $newArray[$j];
$i = $j;
while(($i >= 0) && ($newArray[$i-1] > $temp)){
$newArray[$i] = $newArray[$i-1];
$i--;
}
$newArray[$i] = $temp;
}
return $array;
}
*/
/*
function insertionSort($arrData){
for ($i=1;$i<count($arrData);$i++){
for ($j=$i-1;$j>=0;$j--){
if ($arrData[$j]>$arrData[$j+1]){ //if value on left is bigger than current value
$oldValue = $arrData[$j+1];
$arrData[$j+1] = $arrData[$j];
$arrData[$j] = $oldValue;
}
else {
break; //if value on left is smaller, skip to next position
}
}
}
return $arrData;
}
*/
?>
EDIT: I should also mention that after it returns the errors, it prints the the same array that the first print_r output.
You are using array_count_values($strArray) function which will return an array using the values of $strArray as keys and their frequency in $strArray as values.
So for ex:
$arrayWithVal will be:
array('some_word'=>3,'other_word'=>4);
You are copying this array into $newArray and then later on you are trying to access $newArray with numeric index : $newArray[$j+1] while $newArray is an associative array.
That is why you are getting undefined offset error.
Exact working code for your problem can be :
//this function will pull a string from a txt file and pass characters to an array
function strToArray($file){
if ($handle = fopen($file, 'r')){
$string = fread($handle, filesize($file));
fclose($handle);
}
$strArray = str_split(preg_replace('/\s+/', '', $string)); //regex in preg_replace gets rid of all whitespaces; str_split converts string to array
$arrLen = array_count_values($strArray);
return $arrLen;
}
$arrayWithVal = strToArray("filetest.txt"); //intermediary to pass into next function
print_r($arrayWithVal); //see what I have so far
$newArray = $arrayWithVal;
$test = array();
foreach($newArray as $v){
$test[] = $v;
}
for ($i = 1; $i < count($test); $i++){
for ($j = $i-1; $j >= 0; $j--){
if ($test[$j] > $test[$j+1]){ //if value on left is bigger than current value
$oldValue = $test[$j+1];
$test[$j+1] = $test[$j];
$test[$j] = $oldValue;
//return $newArray;
}
else {
break; //if value on left is smaller, skip to next position
}
}
}
$result = array();
foreach($test as $k => $v){
$keys_array = array_keys($newArray, $v);
foreach($keys_array as $key){
$result[$key] = $v;
}
}
print_r($result);// to see $result array
If your $newArray is:
Array
(
[some] => 4
[r] => 3
[w] => 6
[t] => 1
[a] => 8
[hell] => 4
)
$result array will be :
Array
(
[t] => 1
[r] => 3
[some] => 4
[hell] => 4
[w] => 6
[a] => 8
)
Its good approach if you are learning PHP but otherwise you should just use inbuild php functions for better time performance.
I hope it helps

I want to remove a letter from all the elements in an array and replace it with a string using PHP.

$numbers = array("18339993993","18303839303");
foreach($numbers as $number) {
$number = explode(",", $number);
for($i = 0; $i <= count($number); $i++) {
$number = substr($number,1, 10);
echo $number;
}
please i want to remove the first number in every element in the array and replace it with "999" to all the elements in the array.
I want my output to be like this for each element in the array:
$output[0] = "9998339993993"
$output[1] = "9998303839303"
This should work for you:
(Here I go through every element of the array with array_map(). Then I return each element with 999 at the start plus the original value with an offset of 1 which I get with substr())
<?php
$numbers = array("18339993993","18303839303");
$numbers = array_map(function($v){
return "999" . substr($v, 1);
}, $numbers);
print_r($numbers);
?>
Output:
Array ( [0] => 9998339993993 [1] => 9998303839303 )
Closer to the code in the question:
<?php
$numbers = array("18339993993","18303839303");
$numbers_after = array();
foreach ($numbers as $number){
$number = "999" . substr($number, 1);
array_push($numbers_after, $number);
}
print_r ($numbers_after);
?>
Since there was no regex solution:
$numbers = preg_replace('/^\d/', '999', $numbers);
Easy as that.

Categories