PHP: Adapt number ID to words - php

What do I need to do to convert the number only if all the number matches?
At the moment, it's converting to each number. (I've tried to do a lot and I didn't succeed)
I would like to know if have any way of adapting to only show the word if the number "is complete", otherwise show the word "Doesn't contain a name record".
Example:
When I try to use the number 1987, the output its: Name1 Name9 Name8 Name7, and I want to be only one word: Name1987.
function numberTowords($num)
{
$ones = array(
0 => "Name0",
1 => "Name1",
2 => "Name2",
3 => "Name3",
4 => "Name4",
5 => "Name5",
6 => "Name6",
7 => "Name7",
8 => "Name8",
9 => "Name9",
10 => "Name10",
11 => "Name11",
12 => "Name12",
13 => "Name13",
14 => "Name14",
15 => "Name15",
16 => "Name16",
17 => "Name17",
18 => "Name18",
19 => "Name19",
1987 => "Name1987",
2398 => "Name2398",
);
$num = number_format($num, 2, ".", ",");
$num_arr = explode(".", $num);
$wholenum = $num_arr[0];
$decnum = $num_arr[1];
$whole_arr = array_reverse(explode(",", $wholenum));
krsort($whole_arr, 1);
$rettxt = "";
foreach ($whole_arr as $key => $i) {
while (substr($i, 0, 1) == "0")
$i = substr($i, 1, 5);
if ($i < 20) {
/* echo "getting:".$i; */
$rettxt .= $ones[$i];
} elseif ($i < 100) {
if (substr($i, 1, 1) != "0") $rettxt .= " " . $ones[substr($i, 1, 1)];
} else {
if (substr($i, 0, 1) != "0") $rettxt .= $ones[substr($i, 0, 1)];
if (substr($i, 2, 1) != "0") $rettxt .= " " . $ones[substr($i, 2, 1)];
}
if ($key > 0) {
$rettxt .= " ";
}
}
if ($decnum > 0) {
$rettxt .= " and ";
if ($decnum < 20) {
$rettxt .= $ones[$decnum];
} elseif ($decnum < 100) {
$rettxt .= " " . $ones[substr($decnum, 1, 1)];
}
}
return $rettxt;
}

only show the word if the number "is complete", otherwise show the word "Doesn't contain a name record".
Example: ... number 1987 I want (output) to be only one word: Name1987.
If this is all you need - piece of cake:
<!-- this is only a tool for easy test -->
<form><input name="nr"><input type="submit"></form>
<?php
$pattern = array_merge(range(0,19),[1987,2398]);
$nr = $_GET[nr];
echo in_array($nr,$pattern) ? "Name$nr" : "Doesn't contain a name record";
array_merge() joins arrays, range() is kind of array, in_array() checks if a value exists in an array
more flexible - for cases you omitted in your question
$pattern = [0=>'my name is Zero',
1=>'I am the ONE',
12345=>'this is a number',
'12345'=>'this is a string',
'7x24'=>'all time shift',
999=>'almost thousand',
12=>'call me a dozen'];
echo array_key_exists($nr,$pattern) ? $pattern[$nr] : "Doesn't contain a name record";
// if you don't like shorthand - different notation:
if(array_key_exists($nr,$pattern)){ echo $pattern[$nr];}
else{ echo "Doesn't contain a name record";}
array_key_exists()
Arrays are fast and nice in use. Built-in functions are optimised and that makes them much better than step-by-step manipulations. Debugging a few lines of code is easy, debugging plenty lines of particular manipulations is a nightmare. For most cases in php the only concern is to find the name of built-in function which do it all at once.
I didn't want to limit the numbers (...) want to add more than 200 ids
I didn't limit anything, and it is not that much, even as associative array it wouldn't be big array
more complex - it's time to organise the code structure
function name($x,$arr){
if(in_array($x,range(130,150))){ $name = 'from 130 to 150';} //or (($x >= 130) && ($x <= 150)), or ... etc
else if(in_array($x,range(100,200))){ $name = 'from 100 to 200';}
else if(array_key_exists($x,$arr)){ $name = $arr[$x];}
else{ $name = 'pass';}
$z = ($x[0] == 0) ? 'leading zero' : '∗'; //or if-else instead of Elvis, (substr($x,0,1) == 0) ...
return($z.' '.$name);}
echo '<p>'.name($nr,$pattern).'</p>';
In the name() function, sequence is important for the sub-ranges.
ternary operator a.k.a. Elvis
filter_var() if you like it

Related

How can I replace every second digit to another digit using if else statement in php?

I have a number that a user will put into a form - 12 digits. Every second digit needs to be replaced - if the digit is:
1 then make it 5
2 then make it 1
3 then make it 6
4 then make it 2
5 then make it 7
6 then make it 3
7 then make it 8
8 then make it 4
0 and 9 stay the same.
So for example:
343608111218 will end up being 383307121417.
Here is an example of what I'm currently doing, but I think it is long winded. This is just for the first number, so I'm assuming I could do something else?
$_POST['number'] = '343608111218';
preg_match_all('~(\d)~', $_POST['number'], $pregs);
if($pregs[1][1] === "1") {
$one = 5;
}
elseif ($pregs[1][1] === "2"){
$one = 1;
}
elseif ($pregs[1][1] === "3"){
$one = 6;
}
elseif ($pregs[1][1] === "4"){
$one = 2;
}
elseif ($pregs[1][1] === "5"){
$one = 7;
}
elseif ($pregs[1][1] === "6"){
$one = 3;
}
elseif ($pregs[1][1] === "7"){
$one = 8;
}
elseif ($pregs[1][1] === "8"){
$one = 4;
}
$rep1 = (array_replace($pregs[1],array(1=>$one)));
If there is a way that I can reduce the amount of code, I would be very grateful. Thank you.
One way of doing it is with preg_replace_callback, passing the match of 2 digits in a row and using strtr to replace the 2nd digit appropriately:
$_POST['number'] = '343608111218';
echo preg_replace_callback('~(\d)(\d)~', function ($m) {
return $m[1] . strtr($m[2], '12345678', '51627384');
}, $_POST['number']);
Output:
323304151114
This is based on the description you gave on how to do replacements. However if your expected output reflects the correct way to do the replacements, the replacements have to be the other way around, which is just a question of changing the order of parameters to strtr:
echo preg_replace_callback('~(\d)(\d)~', function ($m) {
return $m[1] . strtr($m[2], '51627384', '12345678');
}, $_POST['number']);
Output:
383307121417
Demo on 3v4l.org
As you are replacing each digit with another, create a lookup string and use the number as the index to the array, all the positions 0-9 are set - even if they are the same value. As the value is a string, you can just use the value as the position of the string and replace it directly...
$value = $_POST['number'];
$trans = "0516273849";
for ( $i = 1; $i < strlen($value); $i+=2 ) {
$value[$i] = $trans[$value[$i]];
}
echo $value;
Edit:
To achieve what is the 'desired' output (although only a guess as to what this should be) you can change the line to...
$trans = "0246813579";
$transform = array(
0 => 0,
1 => 5,
2 => 1,
3 => 6,
4 => 8,
5 => 7,
6 => 3,
7 => 8,
8 => 4,
9 => 9
);
$number = '343608111218';
$num = array_map('intval', str_split($number));
$i = 1;
foreach ($num as $key => $value) {
if (0 == ($i % 2)) {
echo $transform[$value];
} else {
echo $value;
}
$i++;
}
To modernize and refine Nick's regex script, use \K to eliminate the use of capture groups. Arrow function syntax helps to make the script more concise. (Demo)
echo preg_replace_callback(
'/.\K\d/',
fn($m) => strtr($m[0], '12345678', '51627384'),
$_POST['number']
);
Nigel's answer is optimized for performance. Despite counting the string length on every iteration and unnecessarily replacing certain numbers with the same number, it will perform very swiftly because it only makes iterated calls of count(). Because all characters in the input string and the translation string are expected to be single-byte characters, the cooresponding number in the translation string can be accessed by its offset. Here's my version of Nigel's script (Demo)
$value = '343608111218';
$trans = '0516273849';
for ($i = 1, $len = strlen($value); $i < $len; $i += 2) {
$value[$i] = $trans[$value[$i]];
}
echo $value;
Mujuonly's answer can be boiled down a little further. $var & 1 is a bitwise odd check which is just as cryptic as !($var % 2), but is slightly faster (not noticeably). Casting each character as an integer is not necessary and using a string-type translation source is a more succinct technique. (Demo)
$number = '343608111218';
$trans = '0516273849';
foreach (str_split($number) as $i => $d) {
if ($i & 1) {
$number[$i] = $trans[$d];
}
}
echo $number;

Create line breaks in output based on array index

I want to display output like this:
1 2 3 4
5 6 7 8
9 1 2
I've tried this code:
$num = ['1','2','3','4','....'];
$size = sizeof($num) / 4;
foreach ($num as $key => $value) {
echo $value;
if($key >= round($size){
echo "<br>"
}
}
But the output is like this:
1 2 3 4
5
6
7
8
...
Can anyone suggest how to write the loop?
$num= ['1','2','3','4','5','6','7','8','9'];
$size = sizeof($num) / 4;
foreach ($num as $key => $value){
echo $value;
if(($key+1) % 4 == 0){
echo "<br>";
}
}
You can use modulus instead of round. Cool I didn't know about sizeOf! Good to know. Mark this as the right answer pwease if this works!
Another way to do this if you didn't want to write out all the numbers that are in the Num Array is to just push them into an array with a while loop.
$num= [];
$i = 1;
//Set the Num Variable to have as many numbers as you want without having to manually enter them in
while ($i < 100) {
array_push($num, $i);
$i++;
}
//Run the actual code that adds breaks ever 4 lines
$size = sizeof($num) / 4;
foreach ($num as $key => $value){
echo $value;
if(($key+1) % 4 == 0){
echo "<br>";
}
}
Sorry if this answer looks the same as the first answer but I will explain it clearer
To achieve what you want
Step 1: Create a for loop
The loop will start from 1 to it's total size of the array
for ($x = 1; $x <= sizeof($num); $x++){
}
Then inside your loop
you can use ternary for simplicity
This line of code
# if $x variable is equal to limit number which you wanted to break
# $num[$x-1] -> subtract to by 1 because we know array always start at index 0
if ($x % 4 == 0) {
$num[$x-1]."<br>"; #put a break after it
} else {
echo $num[$x-1];
}
is same as this
echo ($x % 4 == 0) ? $num[$x-1]."<br>" : $num[$x-1];
So try this
<?php
$num= ['1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16'];
$size = sizeof($num) / 4;
for ($x = 1; $x <= sizeof($num); $x++){
echo ($x % 4 == 0) ? $num[$x-1]."<br>" : $num[$x-1];
}
DEMO
You can try this:
$numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 8, 19, 20];
$len = 1;
foreach ($numbers as $number) {
echo $number . ' ';
$len++;
if ($len > 4) {
echo '<br>';
$len = 1;
}
}

Assigning Positions to Students, PHP

I am still a novice at PHP scripting.
I have an Array
$students = array(1201=>94,1203=>94,1200=>91, 1205=>89, 1209=>83, 1206=>65, 1202=>41, 1207=>38,1208=>37, 1204=>37,1210=>94);
From the associative array, the key are the student's exam no and the values are the student's scores. Then I used the 2 inbult PHP functions array_keys and array_values to separate the exam nos from the scores.
$exam_nos=(array_keys($students));
$marks=(array_values($students));
Then I passed the $marks array through the code below:
$i=0;
$occurrences = array_count_values($marks);
$marks = array_unique($marks);
echo '<table border="1">';
foreach($marks as $grade) {
if($grade == end($marks))$i += $occurrences[$grade]-1;
echo str_repeat('<tr><td>'.$grade.': '.($i+1).'</td></tr>',$occurrences[$grade]);
$i += $occurrences[$grade];
}
echo '</table><br />';
output:
94: 1
94: 1
94: 1
91: 4
89: 5
83: 6
65: 7
41: 8
38: 9
37: 11
37: 11
And this is closer to what I want; to rank the scores such that if a tie is encountered, 1 or more positions are skipped, occurs at the end the position the items at the end are assigned a position equivalent toi the total number of ranked items. However, it would be much helpful if this could be done without separating the Array into 2 ...
Questions:
(1) I am pulling my hair how, from the $student array I could have something like:
Exam No Score Position
1201 94 1
1210 94 1
1203 94 1
1200 91 4
1205 89 5
1209 83 6
1206 65 7
1202 41 8
1207 38 9
1204 37 11
1208 37 11
(2) I would like to be able to pick any student by exam no and be able to echo or print out her position e.g
the student 1207 is number 9.
I think I need to capture the postions in a variable, but how do I capture them? Well I don't know!
Could the experts help me here with a better way to achieve my 2 goals (please see questions 1 and 2)? I will try any suggestion that will help me disolve the 'metal blockage' I have hit.
If you're pulling out the students from a database (mentioned in the comments), you could retrieve them with the desired format directly using SQL.
However, I'm going to assume that that's not an option. You could do as follows:
$students = array(1201=>94,1203=>94,1200=>91, 1205=>89, 1209=>83, 1206=>65, 1202=>41, 1207=>38,1208=>37, 1204=>37,1210=>94);
arsort($students);// It orders high to low by value. You could avoid this with a simple ORDER BY clause in SQL.
$result = array();
$pos = $real_pos = 0;
$prev_score = -1;
foreach ($students as $exam_n => $score) {
$real_pos += 1;// Natural position.
$pos = ($prev_score != $score) ? $real_pos : $pos;// If I have same score, I have same position in ranking, otherwise, natural position.
$result[$exam_n] = array(
"score" => $score,
"position" => $pos,
"exam_no" => $exam_n
);
$prev_score = $score;// update last score.
}
$desired = 1207;
print_r($result);
echo "Student " . $result[$desired]["exam_no"] . ", position: " . $result[$desired]["position"] . " and score: ". $result[$desired]["score"];
Hope it helps you.
I would use a custom object to process the students individually and store them in an array.
$students = array(1201=>94,1203=>94,1200=>91, 1205=>89, 1209=>83, 1206=>65, 1202=>41, 1207=>38,1208=>37, 1204=>37,1210=>94);
arsort($students); // Sort the array so the higher scores are on top.
$newStudents = array();
$pos = 0;
$count = 0;
$holder = -1; // Assuming no negative scores.
foreach($students as $k=>$v){
$count++; // increment real counter
if($v < $holder || $holder == -1){
$holder = $v;
$pos = $count;
}
$newStudents[] = makeStudent($pos, $v, $k);
// If you want the exam # as the array key.
// $newStudents[$k] = $student;
}
$newStudents = fixLast($newStudents);
// outputs
print_r($newStudents);
foreach($newStudents as $v){
echo "position : " . $v->position . "<br>";
echo "score : " . $v->score . "<br>";
echo "exam : " . $v->exam . "<br>";
}
function makeStudent($pos, $score,$examNo){
$student = new stdClass(); // You could make a custom, but keeping it simple
$student->position = $pos;
$student->score = $score;
$student->exam = $examNo;
return $student;
}
function fixLast($students){
$length = count($students) -1;
$count = 0;
$i = $length;
while($students[$i]->position == $students[--$i]->position){
$count++;
}
for($i = 0; $i <= $count; $i++){
$students[$length - $i]->position = $students[$length - $i]->position + $count;
}
return $students;
}

Create a program with php that will find the missing number in the series of numbers

i need help with a question, I need to write code in php that will
find the missing number in the sequence, regardless of that numbers position in the sequence.
the numbers will increase but the same amount each time.
the output must be only the number that was missing from the initial list, not just the list with the number in it (I have worked that out myself).
example number sequence, $sequence = 3, 5, 9, 11, 13
obviously the number 7 is missing, but I don't know how to do the code, im assuming it would use loops, but i wouldn't even know were to start, It must be in PHP
A more simple way to get the missing number(s) from the sequence, the way I see it:
<?php
$sequence = array(3, 5, 9, 11, 13);
$numbers = array(7, 9, 15);
$single_nr = 7;
function getMissingNumber(array $sequence, $single_nr = null, $numbers = array())
{
// Check if it exists in the sequence array
// check single number
if($single_nr)
{
if(!in_array($single_nr, $sequence))
{
echo $single_nr . " is not in array" . "<br />";
}
}
// check an array of numbers
if($numbers)
{
foreach($numbers as $nr)
{
if(!in_array($nr, $sequence))
{
echo $nr . " is not in array" . "<br />";
}
}
}
}
echo getMissingNumber($sequence, null, $numbers);
?>
Only uses the first three elements to find the interval (needs a 2 out of 3 match) and doesn't validate if the rest of the sequence follow the rule, but also finds more missing elements:
<?php
$sequence = array(3, 5, 9, 13, 15, 17, 21);
// guess
$step = $sequence[1] - $sequence[0];
// validate
if (($sequence[2] - $sequence[1]) != $step) {
if (($sequence[3] - $sequence[2]) != $step) {
$step = $sequence[2] - $sequence[1];
if (($sequence[3] - $sequence[2]) != $step) {
die('first three intervals are all different');
}
}
}
$should = range($sequence[0], $sequence[count($sequence) - 1], $step);
echo 'Missing: ', implode(', ', array_diff($should, $sequence));
<?php
$str="3,5,9,11,13" ;
$arr=explode(',', $str);
$no=array();
for ($i=3; $i <30 ; $i=$i+2) {
$m=$i+2;
if (!(in_array($m, $arr)))
{
$no[]=$m;
}
}
print_r($no);
// OUTPUT- Array ( [0] => 7 [1] => 15 )
?>

How can I simplify a percent (ex. 25%) to a simple statement (ex. 1 out of 4)?

I need to convert an array of numbers and totals into a simple statement.
For example, how can I convert the following, programmatically via PHP, to simple statements like, 1 out of 10, 1 out of 100, and even rounding some (like 2 out of 100 for 9000,400000).
Generate Sample Array:
$arr = array();
for ($i=0; $i < 100; $i++) {
$n = mt_rand(1,1000);
$t = mt_rand(10,100000);
if ($n > $t) continue; // skip!
$arr[] = array($n,$t);
}
/*
// Generates pairs like:
// Array
// (
// [0] => Array ( [0] => 55 [1] => 8774 )
// [1] => Array ( [0] => 814 [1] => 11174 )
// [2] => Array ( [0] => 255 [1] => 32168 )
// ...
// [99] => Array ( [0] => 851 [1] => 24231 )
// )
*/
Run through a function and print simplified results:
foreach ($arr as $a) {
echo $a[0] . '/' . $a[1] . ' ==> ' . simplifyRatio($a[0],$a[1]) . "\r\n";
}
Can you point me in the right direction on how to accomplish this?
Here's the start of a function I'm working on, but the solution is escaping me.
function simplifyRatio($n,$t) {
$p = $n/$t;
if ($p > 0.09) return round($n) . ' out of ' . round($t);
if ($p > 0.009) return round($n) . ' out of ' . round($t);
}
Ideally the denominator should be: 1,2,3...10,20,30...100,200,300...1000,2000,3000...10000,20000,30000...100000 (max)
Assuming always a percentage. You may also want to sprintf $outof before displaying it
function convertPercent($iPercent)
{
// Assume validation on $iPercent
$outof = round(100 / $iPercent);
return "1 out of $outof";
}
For simplicity's sake, I'll assume that you can get your percent in a fraction (ie 25% is 25/100, 0.7% = 7/1000, etc).
You can use Euclid's algorithm to find the GCD of the numerator and the denominator:
http://en.wikipedia.org/wiki/Euclidean_algorithm
In php it'd look something like this:
function gcd ($int1, $int2) {
$tmp = 0;
while ($int1 > 0) {
$tmp = $int1;
$int1 = $int2 % $int1;
$int2 = $tmp;
}
return $int2;
}
This will work as long as $int1 and $int2 are integers greater than 0 (you might want to put in some logic to ensure this). If you need negative numbers, just take the absolute value.
Knowing the GCD, it's easy to figure out the rest:
function reduce($numerator, $denominator) {
$gcd = gcd($numerator, $denominator);
echo ($numerator/$gcd) . " out of " . ($denominator/$gcd);
}
echo reduce(4, 8).'<br>'; // 1 out of 2
echo reduce(38, 897).'<br>'; // 38 out of 897
echo reduce(39, 26).'<br>'; // 3 out of 2
Hope this helps!
I ended up settling for a near match on the pattern 1 out of ___, like so:
function simplifyRatio($n,$t) {
$r = $t/$n;
return '1 out of ' . round($r);
}
// Examples:
$arr = array();
for ($i=0; $i < 100; $i++) {
$n = mt_rand(1,1000);
$t = mt_rand(10,100000);
if ($n > $t) continue; // skip!
$arr[] = array($n,$t);
}
foreach ($arr as $a) {
echo $a[0] . '/' . $a[1] . ' ==> ' . simplifyRatio($a[0],$a[1]) . "\r\n";
}
Example Result:
1000/24819 ==> 1 out of 25
309/50305 ==> 1 out of 163
488/99123 ==> 1 out of 203
322/47610 ==> 1 out of 148
183/54287 ==> 1 out of 297
752/67646 ==> 1 out of 90
240/68854 ==> 1 out of 287
301/81345 ==> 1 out of 270
611/16404 ==> 1 out of 27
522/62992 ==> 1 out of 121
CodePad: http://codepad.org/wu6iOdDq
Initially I had hoped to end up with rounded denominators (10,20...100,200...1000,2000, etc.), but I'm uncertain how to do this well. I'll happily award an answer that cleans up the denominators of the above.

Categories