I have a need for a function that will do the following thing:
If I have a string like this "2 1 3 6 5 4 8 7" I have to insert dashes between pairs of numbers following some rules.
The rules are simple.
Put a dash between two numbers if the first one of the pair is smaller then the one that follows it. Do all possible combinations of this and if a pair already has a dash then the space next to it can't have a dash.
Basically my results for above string would be
2 1-3 6 5 4 8 7
2 1-3 6 5 4-8 7
2 1 3-6 5 4 8 7
2 1 3-6 5 4-8 7
2 1 3 6 5 4-8 7
I did create a function that does this but I am thinking it is pretty sluggish and I don't want to taint your ideas with it. If possible I would like to know how you guys are thinking about this and even some pseudo code or code would be great.
EDIT 1:
here is the code I have so far
$string = "2 1 3 6 5 4 8 7";
function dasher($string){
global $dasherarray;
$lockcodes = explode(' ', $string);
for($i = 0; $i < count($lockcodes) - 1; $i++){
if(strlen($string) > 2){
$left = $lockcodes[$i];
$right = $lockcodes[$i+1];
$x = $left . ' ' . $right;
$y = $left . '-' . $right;
if (strlen($left) == 1 && strlen($right) == 1 && (int)$left < (int)$right) {
$dashercombination = str_replace($x, $y, $string);
$dasherarray[] = $dashercombination;
dasher($dashercombination);
}
}
}
return array_unique($dasherarray);
}
foreach(dasher($string) as $combination) {
echo $combination. '<br>';
}
Perhaps this will be helpful in terms of offering different methods to parse the string.
$str="2 1 3 6 5 4 8 7";
$sar=explode(' ',$str);
for($i=1;$i<count($sar);$i++)
if($sar[$i-1]<$sar[$i])
print substr_replace($str,'-',2*($i-1)+1,1) . "\n";
Note that the code expects only single digits numbers in the string.
Note that the code expects that the string is formatted as per your example. It would be good to add some sanity checks (collapse multiple spaces, strip/trim blanks at the beginning/end).
We can improve upon this by finding all the spaces in the string and using them to index substrings for comparison, still assuming that only a single spaces separates adjacent numbers.
<?php
$str="21 11 31 61 51 41 81 71";
$letter=' ';
#This finds the locations of all the spaces in the strings
$spaces = array_keys(array_intersect(str_split($str),array($letter)));
#This function takes a start-space and an end-space and finds the number between them.
#It also takes into account the special cases that we are considering the first or
#last space in the string
function ssubstr($str,$spaces,$start,$end){
if($start<0)
return substr($str,0,$spaces[$end]);
if($end==count($spaces))
return substr($str,$spaces[$start],strlen($str)-$spaces[$start]);
return substr($str,$spaces[$start],$spaces[$end]-$spaces[$start]);
}
#This loops through all the spaces in the string, extracting the numbers on either side for comparison
for($i=0;$i<count($spaces);$i++){
$firstnum=ssubstr($str,$spaces,$i-1,$i);
$secondnum=ssubstr($str,$spaces,$i,$i+1) . "\n";
if(intval($firstnum)<intval($secondnum))
print substr_replace($str,'-',$spaces[$i],1) . "\n";
}
?>
Note the explicit conversion to integers in order to avoid lexicographic comparison.
Related
This comment looks like it would work if the author included the value for $numbers. They say it is some type of array, but don't provide enough information to replicate it. I picture some hard coded array ranging from 0 to 9, but I can't help think that such an array would miss numbers greater than 9. What does the numbers array in this example look like?
$text = "1 out of 23";
if(preg_match_all('/\d+/', $text, $numbers))
$lastnum = end($numbers[0]);
I would just post a comment asking whoever wrote that to paste the value for $numbers, but it says I need reputation points to do that.
See How do I grab last number in a string in PHP?
To answer your initial question print_r() can be used to output all contents of an array. e.g. print_r($numbers)
https://3v4l.org/2jA1b
To explain the code:
\d is a single number
+ is a quantifier meaning one or more of the previous character or group
so this would find all numbers in a string. The $numbers[0] would be all numbers, 1 per index, and the end() pulls to the last number/index. Each index would be a number, the 0 is all matches, each indice at the root level is a capture group.
This code wouldn't work as intended for decimals or comma delimited integers. In those cases the numbers would be split up at the delimiter. 1.0 would become 1 and 0 (2 different numbers).
You could rewrite this as:
$text = "1 out of 23";
if(preg_match('/.*\K\D\d+/', $text, $numbers))
echo $numbers[0];
so the end function is not needed. This pulls everything until the last number then forgets everything before the last number.
What you are trying to do is likely easier using preg_split instead of preg_match_all. We can split the input text by the matched regex (digits) and then rebuild the string while incrementing the numbers as we go.
<?php
function incrementNumbers($text) {
// NOTES:
// parenthesis are important in the regex in order to return the captured values
// the -? will capture negative numbers too if necessary
// PREG_SPLIT_DELIM_CAPTURE allows the captured values to be returned too
$split = preg_split('/(-?\d+)/', $text, -1, PREG_SPLIT_DELIM_CAPTURE);
$return = '';
foreach($split as $i => $s) {
// because we didn't use PREG_SPLIT_NO_EMPTY, $split[0] will either be an empty string if
// $text began with a number, or the text before the first number. Either way, $split alternates
// between non-number [0], number [1], non-number [2], number [3], etc which is why we can detect
// even or odd indexes to determine if this is a number that needs to be incremented or not
if ($i % 2 === 0) {
$return .= $s;
} else {
$return .= (intval($s) + 1);
}
}
return $return;
}
Examples:
echo incrementNumbers("1 out of 23 with 1 and 1 and 24 and 23");
echo incrementNumbers("1 1 2 2 3 3 2 2 1 1");
echo incrementNumbers("0 1 2 3 4 5 6 7");
echo incrementNumbers("-3 -2 -1 0 1 2 3 4 5 6 7");
echo incrementNumbers("there are no numbers in this text");
echo incrementNumbers("does not start 999 with a number 123 nor end 17 with a number");
Outputs:
2 out of 24 with 2 and 2 and 25 and 24
2 2 3 3 4 4 3 3 2 2
1 2 3 4 5 6 7 8
-2 -1 0 1 2 3 4 5 6 7 8
there are no numbers in this text
does not start 1000 with a number 124 nor end 18 with a number
Working example at https://3v4l.org/iKskO
I have a PHP problem.
I need to write a number from a sets of digits 0-9. Each set has 10 digits, each digit once.
I need to count the number of sets that I have to use to write the number.
For example number 10 is written from one set, but number 300 uses 2 sets because it has two zeros.
But, the problem is that 6 and 9 are considered the same. They can be rotated by 180 degrees.
Number 266 will be using one set, 369 also is using one set, but 5666 is using 2 sets.
I would be very grateful if you could somehow help me.
Here is how I have started and stuck up, have no more clue how to loop through it. Tried many things, nothing successful.
<?php
function countSet($num) {
$array = str_split($num);
$statarr = [0,1,2,3,4,5,6,7,8,9];
$a1 = $array; $a2 = $statarr;
$result = array_intersect($a1,$a2);
$count = array_count_values($result); }
?>
If you just need to know how many sets you need for a number, you can solve by counting the numbers. For the case of the 9, just replace every 9 by a 6 and divide the number of 6 by two. Something like this (sorry if there's any syntax error, I'm on mobile):
function countSet($input) {
// Convert the input into a string and replace every 9 by a 6. Then convert it to array
$numbers = str_split(str_replace("9", "6", strval($input)));
// Count occurrences for each number
$usedNumbers = array_count_values($numbers);
// If we have a 6, must divide it by 2 (6 represents 6 and 9
if (array_key_exists("6", $usedNumbers)) {
$usedNumbers["6"] = ceil($usedNumbers["6"] / 2);
}
// Now we just need to know the max number of occurrences for a single number as our result.
return max($usedNumbers);
}
See an online demo here
Let’s say I have a series of numbers like:
12345678910111213141516... (until unlimited)
Then I would like to get a number from it by given digit. For example:
Digit 10th: 1
Digit 17th: 3
...
I have tried to make the algorithm to do it by using PHP but it always showed me an error due to the looping that I made was out of memory size if the given digit that I gave is more than 10.000.000. Allowed Memory Size of 134217728 Bytes Exhausted
How do I deal with this without having to modify memory_limit on php.ini file?
Here are what I have tried to figure the algorithm out: I benchmark the maximum of upper limit of the loop that my local machine could handle, and I found out it's 10.000.000, then I assumed I need to make a separate loop if the given digit/parameter is more than 10.000.000. But in the end I still got that error of out of memory size. Really grateful in advance.
<?php
/*
* benchmark result:
* max digit = 10.000.000
*/
$benchmarkedDigit = 10000000;
$digit = 1000000000000; // it could be dynamically assigned, i.e. a parameter. In this case will show an error since the given digit is 10 trillion
$s = '';
if ($digit > $benchmarkedDigit) {
$mod = fmod($digit, $benchmarkedDigit);
$div = $digit / $benchmarkedDigit;
for ($x = 1; $x <= $div; $x++) {
$upperLimit = ($x * $benchmarkedDigit);
for ($y = ($upperLimit - $benchmarkedDigit + 1); $y <= $upperLimit; $y++) {
$s .= $y;
}
// so it could be:
// 1 - 10.000.000
// 10.000.001 - 20.000.000
// 20.000.001 - 30.000.000
// ...
}
// loop for the rest of the fmod(), if its result is not 0
for ($i = ($upperLimit + 1); $i <= ($upperLimit + $mod); $i++) {
$s .= $i;
}
} else {
for ($x = 1; $x <= $digit; $x++) {
$s .= $x;
}
}
echo substr($s, ($digit - 1), 1);
You can use the fact that there's always 10^n - 10^(n-1) number of n-digit long numbers (even 1 digit, because I see 0 is not there).
With this knowledge, you can skip potentially huge number of numbers.
You start with n=1, and check if the number of n digit numbers is lower than the desired digit. If it is, then reduce the number of n digit numbers from the desired number, increase n by one and start again.
For example: you want to know the 512th digit in that number
Is the number of 1 digit numbers (10) lower than the desired digit (512)?
Yes, so the desired digit should be reduced by that many (512 - 9).
Is the number of 2 digit numbers (90) lower than the desired digit (503 now)?
Yes, so the desired digit should be reduced by that many (503 - 90).
Is the number of 3 digit numbers (900) lower than the desired digit(413 now)?
No, so the desired digit is one of the digits of a 3 digit number.
413 / 3 is 137 (rounded down), so it's one of the digits of the 137th 3 digit numbers (so 237).
413 % 3 (modulo) is 2, so it's the 2nd digit, so it's supposed to be 3.
There can be miscalculations in this, but the overall logic should not be far.
Edit: you could also use a generator, but this can increase the runtime for big numbers
function getNthDigit() {
for ($i = 0;; ++$i) { // Start with 0, which is the 0-th digit
foreach (str_split((string)$i) as $digit) {
yield $digit;
}
}
}
$desiredDigit = 512;
foreach (getNthDigit() as $number => $digit) {
if ($number == $desiredDigit) {
break;
}
}
// $digit should be the desired digit
<?php
function getDigit($Nth){
if($Nth < 10) return $Nth;
$no_of_digits = 1;
$current_contribution = 9;
$actual_length = 9;
$prev_length = 0;
$starting_number = 1;
$power_of_10 = 1;
while($actual_length < $Nth){
$no_of_digits++;
$current_contribution *= 10;
$prev_length = $actual_length;
$actual_length += ($current_contribution * $no_of_digits);
$power_of_10 *= 10;
$starting_number *= 10;
}
$Nth = $Nth - $prev_length;
$offset = $Nth % $no_of_digits === 0 ? intval($Nth / $no_of_digits) - 1 : intval($Nth / $no_of_digits);
$number = strval($starting_number + $offset);
for($i=1;$i<=$no_of_digits;++$i){
if(($Nth - $i) % $no_of_digits === 0){
return $number[$i-1];
}
}
}
// first 100 Digits
for($i=1;$i<=100;++$i){
echo getDigit($i),PHP_EOL;
}
Demo: https://3v4l.org/3l0I7
Algorithm:
To find the nth digit, we will first find the number and then which digit of that number to choose as an answer.
Find the number:
If we carefully observe, the series increases in a sequential manner, such as shown in the table.
Table:
| Digits| Total numbers(of current digit)| Total Digits | Total digits of whole string |
|-------|--------------------------------|--------------|-------------------------------|
| 1 | 9 | 9 | 9 |
| 2 | 90 | 180 | 189 |
| 3 | 900 | 2700 | 2889 |
| 4 | 9000 | 36000 | 38889 |
The above table shows us that if we want to find, let's say 500th digit, then it's some digit of 3 digit number. If we go for 17th digit, then it's some digit of a 2 digit number and so on.
Now, let's take 200th digit as an example. Since it's less than 2889 and greater than 189, it's from a 3 digit number.
What we would do is breakdown the 200 into a smaller number such as 200 - 189 = 11. This 11 means that it's 11th digit of some 3 digit number which started with initial 3 digit number of 100(the starting number for 3 digit).
Now, we do 11 / 3(where 3 is number of digits) and get the quotient as 3. This 3 means that it's 3 numbers past the starting number 100, which we can say as 100 + 3 = 103(since it's 100,101,102 and then the 4th one as 103).
Now, we came to know that the number is 103. All is left to find out is which digit from 103.
Note that sometimes we come across a corner case of even divisibility such as 12 / 3. In this case, we subtract 1 from the quotient since our series of 3 digits starts from 100 and not 101( and so on and so forth for other digits).
Find out the digit:
Now, we know that the number is 103 for a 200 th digit( a.k.a 11 as we calculated above). To find out which one, we write down numbers of 3 digits in sequence and closely observe them.
Sequence:
1 0 0 1 0 1 1 0 2 1 0 3 1 0 4 1 0 5 1 0 6
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
If you observe, you can understand that the most MSB digit follows a sequence of 1,4,7,10,13 etc. Second most MSB follows a sequence of 2,5,8,11,14 etc and the last MSB(which is LSB) follows a sequence of 3,6,9,12,15 etc.
So, from th above sequence, it's pretty evident that 11(which we got after breaking down 200 initially) belongs to a sequence of the 2nd most MSB digit.
So, the final answer from 103 is 0 (the 2nd digit from left).
$num = '12345678910111213141516';
echo $num[16];
Result: 3
I have two strings,one string which is an output from an API and
another which is stored in the MYSQL Database as longtext.I am trying
to compare these two strings,so here's what I did:
echo $stringfromMyDatabase;
echo "<br">;
echo $stringfromMyApi;
echo "<br>";
echo strcmp($stringfromMyDatabase,$stringfromMyapi);
echo "<br>";
echo "StringfrommyDatabase :".strlen($stringfromMyDatabase)."and StringfromApi:".strlen($stringfromMyApi);
and Here's the output I obtained:
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
1
StringfrommyDatabase :25 and StringfromApi:17
Although the string looks exactly similar while echoing them out,How
do I know how and where these two strings differ and How do i print
the two strings with all special characters enlcosed?
Any help with proper explanation will be highly appreciated!
use var_dump($stringfromMyDatabase, $stringfromMyApi) and look at this.
The strings are different according to the strlen you performed on them. I am pretty sure that your database stored the string with additional space characters (blank spaces, tabs, ...).
Try this:
$len = strlen($stringfromMyDatabase);
for ($i = 0; $i < $len; $i++) {
if ($stringfromMyDatabase[$i] != $stringfromMyapi[$i])
echo "--{$stringfromMyDatabase[$i]}-- (code " . ord($stringfromMyDatabase[$i]) .
") != --{$stringfromMyapi[$i]}-- (code " . ord($stringfromMyapi[$i]) . ") # char pos {$i}\n";
}
This will show you where the strings differ and what are the (possibly non printable) characters that are different.
What exactly does this mean?
$number = ( 3 - 2 + 7 ) % 7;
It's the modulus operator, as mentioned, which returns the remainder of a division operation.
Examples: 3%5 returns 3, as 3 divided by 5 is 0 with a remainder of 3.
5 % 10 returns 5, for the same reason, 10 goes into 5 zero times with a remainder of 5.
10 % 5 returns 0, as 10 divided by 5 goes exactly 2 times with no remainder.
In the example you posted, (3 - 2 + 7) works out to 8, giving you 8 % 7, so $number will be 1, which is the remainder of 8/7.
It is the modulus operator:
$a % $b = Remainder of $a
divided by $b.
It is often used to get "one element every N elements". For instance, to only get one element each three elements:
for ($i=0 ; $i<10 ; $i++) {
if ($i % 3 === 0) {
echo $i . '<br />';
}
}
Which gets this output:
0
3
6
9
(Yeah, OK, $i+=3 would have done the trick; but this was just a demo.)
It is the modulus operator. In the statement $a % $b the result is the remainder when $a is divided by $b
Using this operator one can easily calculate odd or even days in month for example, if needed for schedule or something:
<?php echo (date(j) % 2 == 0) ? 'Today is even date' : 'Today is odd date'; ?>
% means modulus.
Modulus is the fancy name for "remainder after divide" in mathematics.
(numerator) mod (denominator) = (remainder)
In PHP
<?php
$n = 13;
$d = 7
$r = "$n % $d";
echo "$r is ($n mod $d).";
?>
In this case, this script will echo
6 is (13 mod 7).
Where $r is for the remainder (answer), $n for the numerator and $d for the denominator. The modulus operator is commonly used in public-key cryptography due to its special characteristic as a one-way function.
Since so many people say "modulus finds the remainder of the divisor", let's start by defining exactly what a remainder is.
In mathematics, the remainder is the amount "left over" after
performing some computation. In arithmetic, the remainder is the
integer "left over" after dividing one integer by another to produce
an integer quotient (integer division).
See: http://en.wikipedia.org/wiki/Remainder
So % (integer modulus) is a simple way of asking, "How much of the divisor is left over after dividing?"
To use the OP's computation of (3 - 2 + 7) = 8 % 7 = 1:
It can be broken down into:
(3 - 2 + 7) = 8
8 / 7 = 1.143 #Rounded up
.143 * 7 = 1.001 #Which results in an integer of 1
7 can go into 8 1 time with .14 of 7 leftover
That's all there is to it. I hope this helps to simplify how exactly modulus works.
Additional examples using different divisors with 21.
Breakdown of 21 % 3 = 0:
21 / 3 = 7.0
3 * 0 = 0
(3 can go into 21 7 times with 0 of 3 leftover)
Breakdown of 21 % 6 = 3:
21 / 6 = 3.5
.5 * 6 = 3
(6 can go into 21 3 times with .5 of 6 leftover)
Breakdown of 21 % 8 = 5:
21 / 8 = 2.625
.625 * 8 = 5
(8 can go into 21 2 times with .625 of 8 leftover)