PHP: Multiple Unique Random Integers In A Specific Range - php

I want to create 8 random integers, that are unique and in the range between 0 and 99.
Is there a neater solution, than the one that I thought of?
<?php
do {
$rnd1 = rand(0,99);
$rnd2 = rand(0,99);
$rnd3 = rand(0,99);
$rnd4 = rand(0,99);
$rnd5 = rand(0,99);
$rnd6 = rand(0,99);
} while (($rnd1 == $rnd2) ||
($rnd1 == $rnd3) ||
($rnd1 == $rnd4) ||
($rnd1 == $rnd5) ||
($rnd1 == $rnd6) ||
($rnd2 == $rnd3) ||
($rnd2 == $rnd4) ||
($rnd2 == $rnd5) ||
($rnd2 == $rnd6) ||
($rnd3 == $rnd4) ||
($rnd3 == $rnd5) ||
($rnd3 == $rnd6) ||
($rnd4 == $rnd5) ||
($rnd4 == $rnd6) ||
($rnd5 == $rnd6) );
?>

Try the code below.
It will create an array containing 8 random values between 0 and 99 while checking if they have been added already to ensure they are unique across.
$numbers = array();
while ( count($numbers) <= 8 ) {
$x = mt_rand(0,99);
if ( !in_array($x,$numbers) ) {
$numbers[] = $x;
}
}
print_r($numbers);
Also see these two Q&A's about using mt_rand vs. rand
Difference between mt_rand() and rand()
What's the disadvantage of mt_rand?

This is an optimized version that relies on the array indexes. The complexity of this solution is linear rather than n2 as in #AlexAndrei's answer. It relies on using array indexes as the guarantee there are no duplicates so there is no need to add the overhead of in_array.
$random_numbers = [];
do {
$rand = rand(0, 99);
$random_numbers[$rand] = $rand;
} while( count($random_numbers) < 9 );
$random_numbers = array_values($random_numbers); // This strips the keys
print_r($random_numbers);
If you are using a foreach you can even drop the array_values call which would also increase the speed of your code, but the numbers in the array will be in the form: [ a => a, b => b, ... ]

$rnds = [];
do {
$newRnd = rand(0, 99);
$rnds[] = $newRnd;
} while(in_array($newRnd, $rnds) && count($rnds) < 9);
print_r($rnds);

Related

PHP Variable declaration not working in Laravel 5.4

I have the following code in a Laravel 5.4 Blade view:
#php($strVal = $character->Strength)
#php($strMod = 0)
<?php
if ($strVal == 10 || 11) {
$strMod = 0;
} elseif ($strVal == 12 || 13) {
$strMod = 1;
} elseif ($strVal == 14) {
$strMod = 2;
} else {
$strMod = 2;
}
?>
It takes data from a MySQL table.
$strVal is an int from the table. The code creates a var called $strMod and goes through a number of if/elseif statements to see what it will be equal to.
It's shown on a webpage as follows:
<div class="huge charMod">+{{$strMod}}</div>
My issue is that it displays as "+0" no matter what strVar equals. strVar is working fine, I can pull it from the DB and display it via {{ $strVal }} but strMod refuses to take a value other than 0.
$strVal == 10 || 11 will always return true
Because that's not how comparisons work in PHP. The == operator has a higher precedence than || operator, so it will be performed first.
It means that $strVal == 10 || 11 gets turned into false || 11 .. which is true.
Instead of that code, I would recommend:
$map = [
10 => 0,
11 => 0,
12 => 1,
13 => 1,
// you dont actually need 14, because default value is aready 2
];
$result = 2;
if (array_key_exists($strVal, $map)) {
$result = $map[$strVal];
}
$strVal = $result;
Or, if you are using PHP 7.0+ it all can actually be written as:
$map = [10 => 0, 11 => 0, 12 => 1, 13 => 1];
$strVal = $map[$strVal] ?? 2;
You need to change your if checks to
if ($strVal == 10 || $strVal == 11) {
$strMod = 0;
} elseif ($strVal == 12 || $strVal == 13) {
$strMod = 1;
} elseif ($strVal == 14) {
$strMod = 2;
} else {
$strMod = 2;
}
if ($strVal == 10 || 11) will always return true. If you want to check two values you need to specify that by using the variable == value again as in the example above.

How to do decompose conditional refactoring?

I've this situation in code where i think the code is unnecessary complex and i believe i can refactor it to make it more easier to understand and read.
So i googled about it and found decompose conditional refactoring, but i'm still in doubt how to do refactoring
if(count($bagTypes) == 1 && (array_key_exists('type1', $bagTypes)
|| array_key_exists('type2', $bagTypes)
|| array_key_exists('type3', $bagTypes))){
$flag = 1;
}
if(count($bagTypes) == 2 && (
(array_key_exists('type1', $bagTypes) && array_key_exists('type2', $bagTypes)) ||
(array_key_exists('type1', $bagTypes) && array_key_exists('type3', $bagTypes)) ||
(array_key_exists('type2', $bagTypes) && array_key_exists('type3', $bagTypes)))
){
$flag = 1;
}
Is there any better way of doing this?
You could try something like this:
$arrayKeys = array(
'type1',
'type2',
'type3'
);
$bagTypesKeys = array_keys($bagTypes);
if ((count($bagTypes) == 1 && count(array_diff($arrayKeys, $bagTypesKeys)) < 3)
|| (count($bagTypes) == 2 && count(array_diff($arrayKeys, $bagTypesKeys)) < 2))
{
$flag = 1;
}

PHP: Sort array according to another array of different length

I have two arrays of different length:
$paths_table = array("TS-0007_a.jpg", "TS-0040_a.JPG", "TS-0040_b.JPG", "TS-0040_f.JPG", "TS-0041_a.JPG", "TS-0041_b.JPG");
$order_table = array("TS-0040","TS-0007","TS-0041");
and I want to sort the first one using the second so that the output will be the array
$final_table = array("TS-0040_a.JPG", "TS-0040_b.JPG", "TS-0040_f.JPG", "TS-0007_a.jpg", TS-0041_a.JPG", "TS-0041_b.JPG")
Assuming that I'm going to use
strpos($paths_table[$i], $order_table[$j]);
to check if the string of $order_table is included in any of the $paths_table.
How can I accomplish this?
Preprocess the array so that each item contains an index of its prefix (that is, turn 'TS-0007_a.jpg' into [1,'TS-0007_a.jpg']):
foreach($paths_table as &$v) {
foreach($order_table as $n => $o)
if(strpos($v, $o) === 0) {
$v = [$n, $v];
break;
}
}
sort the array:
sort($paths_table);
and remove indexes:
foreach($paths_table as &$v)
$v = $v[1];
The following piece of code can off course be optimized in several ways, but for the sake of clarity I didnt.
$paths_table = array("TS-0007_a.jpg", "TS-0040_a.JPG", "TS-0040_b.JPG", "TS-0040_f.JPG", "TS-0041_a.JPG", "TS-0041_b.JPG");
$order_table = array("TS-0040","TS-0007","TS-0041");
$sorter = new PrefixSorter($order_table);
$output = usort($paths_table, array($sorter, 'sort'));
var_dump($paths_table);
class PrefixSorter {
private $prefixes;
function __construct($prefixes) {
$this->prefixes = $prefixes;
}
function sort($path1, $path2) {
$prefix1 = -1;
$prefix2 = -1;
foreach($this->prefixes as $index=>$prefix) {
if (substr($path1, 0, strlen($prefix)) == $prefix) $prefix1 = $index;
if (substr($path2, 0, strlen($prefix)) == $prefix) $prefix2 = $index;
}
if (($prefix1 == -1 && $prefix2 == -1) || $prefix1 == $prefix2) {
return 0;
}
else if ($prefix1 == -1 || $prefix1 > $prefix2) {
return 1;
}
else if ($prefix2 == -1 || $prefix1 < $prefix2) {
return -1;
}
}
}
I made a few assumptions:
You want to sort on the prefixes given in order_table
Prefixes not given are put at the back unordered.
You can off course change the code to match on string containment instead of prefixing

Check variable equals a certain number

I need to check to make sure a variable equals either 5, 10, 50 or 100. If it doesn't then I want to set it to 5. Can someone tell me what's wrong with this IF statement?
if (isset($_REQUEST['number']) && $_REQUEST['number'] !== "5" || $_REQUEST['number'] !== "10" || $_REQUEST['number'] !== "50" || $_REQUEST['number'] !== "100") {
$number = 5;
} else {
$number = $_REQUEST['number'];
}
You need to break up your logic to overcome operator precedence. When in doubt, use parenthesis.
I also inverted the logic. It reads more naturally.
if (isset($_REQUEST['number']) && ($_REQUEST['number'] == "5" || $_REQUEST['number'] == "10" || $_REQUEST['number'] == "50" || $_REQUEST['number'] == "100")) {
  $number = $_REQUEST['number'];
} else {
  $number = 5;
}
While the above works, you could also streamline it with something like in_array().
isset($_REQUEST['number']) && in_array($_REQUEST['number'], array(5, 10, 50, 100))
Try:
if (isset($_REQUEST['number']) && ($_REQUEST['number'] == "5" || $_REQUEST['number'] == "10" || $_REQUEST['number'] == "50" || $_REQUEST['number'] == "100")) {
$number = $_REQUEST['number'];
} else {
$number = 5;
}
You've got some very confusing code. Does nothing you said you wanted.
this should be it:
if (isset($_REQUEST['number']) && in_array($_REQUEST['number'], array(5, 10, 50, 100))) {
$number = (int) $_REQUEST['number'];
} else {
$number = 5;
}
Combined from other answers so thank everyone :)
You need to swap things around a bit:
if (!isset($_REQUEST['number']) || ($_REQUEST['number'] !== "5" && $_REQUEST['number'] !== "10" && $_REQUEST['number'] !== "50" && $_REQUEST['number'] !== "100")) {
$number = 5;
} else {
$number = $_REQUEST['number'];
}
Narration of the above: if number isn't set, make it 5. If it is set, but isn't 5, 10, 50, or 100, set it to 5. Otherwise, leave it as-is.
It may be easier in the long run to break the logic up into a different format to try to be a bit clearer, rather then having a single 'if' statement.
$acceptable = array(5, 10, 50, 100);
$number = null;
if (isset($_REQUEST['number']) {
$number = intval($_REQUEST['number']);
}
if (!in_array($number, $acceptable)) {
$number = 5;
}
But with keeping it as a single if statement:
if (
isset($_REQUEST['number']) && (
$_REQUEST['number'] === "5" ||
$_REQUEST['number'] === "10" ||
$_REQUEST['number'] === "50" ||
$_REQUEST['number'] === "100"
)
) {
$number = $_REQUEST['number'];
} else {
$number = 5;
}
Although iMoses, and others already laid down the basics of simplifying your routine, I would suggest making the in_array() check more strict. If you don't and $_REQUEST['number'] would, for instance equal '10F', it would also pass.
// I like to define default values up front.
$number = 5;
// since $_REQUEST['number'] should always be a string
// make in_array() check strictly against these string values
$allowedNumbers = array( '5', '10', '50', '100' );
// make in_array check strictly
if( isset( $_REQUEST['number'] ) && in_array( $_REQUEST['number'], $allowedNumbers, true ) )
{
// get proper integer value
$number = intval( $_REQUEST['number'] );
}
var_dump( $number );

PHP ElseIf Statement with Numbers

The user can only enter a number between 1 and 5 - if they enter 0, leave the field blank or enter a number greater than 5 it will be default reset to 5. 1,2,3,4 are accepted otherwise.
$max=mysql_real_escape_string($_POST["max"]);
if ($max=="0" || $max==""){
$max_r="5";
} elseif ($max > "5"){
$max_r="5";
} else {
$max_r=$max;
}
However it always spits out 5.
Well, you're comparing strings and not integers. Try $max = (int) $_POST['max'] and don't wrap the values in quotes. Then, you can always escape $max before writing it to the DB.
$max = (int) $_POST['max'];
if ( ! $max || $max > 5){
$max_r = 5;
} else {
$max_r = $max;
}
Or, you could go one-liner FTW:
$max_r = ( ! $max || $max > 5) ? 5 : $max;
$max = intval($_POST['max']);
if($max < 0 || $max > 5){
$max = 5;
}

Categories