How to sort each numerical value in a number? - php

I am making a PHP login/register form and to confirm whether someone is actually human and not a bot I am generating a random value that has to be written in a certain way.
For example:
Please write the following number in an increasing manner: 34745
The user should write 34457 and only then will the confirmation work.
The thing is I know how to use the rand() function, that's how I generate the number. But the problem is I do not know how to make PHP sort the generated number's numerical values (for ex.: 64348 -> 34468).
How do I do this? I hope there is a single function for that, as I've seen numerous ways to sort arrays and since they have indexes I only suppose that it should be possible to sort a number's values.

<?php
$number = str_split("647214");
sort($number);
$number = implode($number);
echo $number;
?>
Demo: http://codepad.viper-7.com/RepImd

Instead of using an integer to hold the complete number you could create an array of size n (n is the number of digits). Iterate over the array and use rand() to create random numbers from 0-9 in each position of the array. Now you have an array which can be sorted by using standard sort functions.

I don't think it has single function, but you can make this.
$num = 34745;
$chars = preg_split('/ /', $num, -1, PREG_SPLIT_OFFSET_CAPTURE);
sort($chars);
$res = implode("", $chars);
echo $res;
I didn't tested this, but I hope it works!

Related

Generate random number with a certain prefix what am i doing wrong

I've been playing about with the uniqid but it started giving me the 13 long string.
I'm looking for a prefix of 100 with up to 6 random numbers afterwards
thanks any help appreciated
function generate_order(){
$order_ref="";
$a=uniqid(prefix,100);
$num4=array('0','1','2','3','4','5','6','7','8','9');
$num=rand(0,9);
$num2=rand(0,9);
$num3=rand(0,9);
shuffle($num4);
//now the final
$order_ref = $num4[0].$num4[3].$num.$num4[1].$num2.$num4[2].$num3.$num4[4];
}
I've got some remakrs to the code above:
Why are you doing a shuffle() on an array with numbers ranging from 1 to 9? This is the same as doing rand(1,9)
Taking point one into account, using rand(10000000, 99999999) will give you the same result.
$a=uniqid(prefix,100) is not used in your function
The prefix in uniqid() should be a string.
Your function doesn't return. You should use return $order_ref;
Hope these will help you fix your function.
In response to your comment
$order_ref = '100'.rand(100000, 999999);
Additional suggestions
If you are planning to use this as an order reference as I suspect, I do not recommand just using random numbers. This will give you a big chance of having duplicate numbers.
Instead, I suggest using $order_ref = '100'.date('u').rand(10, 99);. This will give you a random number based on the current time and thus prevent (or at least minimize) the chance of duplicate order references.
If you want 100 before your result, then use the prefix to enter your desired string
Using uniqid(100) should give you the desired result.
Here is how I would do
1. Define your prefix
2. Generate random number
3. Concat both
$prefix="some_prefix";
$rand_no = rand(1,100);
$rand_no_with_prefix = $prefix.$rand_no;
You can Google for exact syntax and functions.
This is just basic logic I would follow.
Hope it helps.
Also step 4 would be to parse if required(if concated random number needs to be integer)

filling an array with array_pad

I am currently working on a site where I have an array that must contain 8 values.
I generate a random number and write it into my array, after that i would liek to check if this number was infact 8 character long. If this was not the case it should be filled with leading zero's.
Here is the code i am using
$number=rand(0,255);
// convert the number to binary and store it as an array
$states=str_split(decbin($number),1);
echo '<pre>'.print_r($states,true).'</pre>';
// in case the number is not 8 bit long make it an 8 bit number using array_pad
if(count($states)<8){
$states = array_pad($states,count($states)-8,"0");
}
The problem is now that it never fills up the array even if the array only consists of 3 or 4 entrys.
Thanks for the help.
Edit :Thanks to everyone for awnsering so quickly the solution provided by Suresh Kamrushi is working.
instead of
$states = array_pad($states,count($states)-8,"0");
Try like this:
$number=rand(0,255);
// convert the number to binary and store it as an array
$states=str_split(decbin($number),1);
echo '<pre>'.print_r($states,true).'</pre>';
// in case the number is not 8 bit long make it an 8 bit number using array_pad
if(count($states)<8){
$states = array_pad($states,8,"0");
}
print_r($states);
PHP fiddle: http://phpfiddle.org/main/code/a1d-m97
If I understand correctly you don't need count($states) - 8:
$states = array_pad($states, -8, "0");
Which will pad the array to a size of 8, with leading zeroes
For array_pad the second argument is the size you want the array to be, not the number of items you want to add to it.
So just do:
if(count($states)<8){
$states = array_pad($states,8,"0");
}
Or, as array_pad has no effect if your array is already big enough, you don't even need the if(count($states)<8) part.

Random integer with conditions

I have a PHP script where I have an array of integers, let's say $forbidden.
I want to get a random integer from 1 to 400 that is not in $forbidden.
Of course, I don't want any loop which breaks when rand gives a working result. I'd like something more effective.
How do you do this ?
Place all forbidden numbers in an array, and use array_diff from range(1,400). You'll get an array of allowed numbers, pick a random one with array_rand().
<?php
$forbidden = array(2, 3, 6, 8);
$complete = range(1,10);
$allowed = array_diff($complete, $forbidden);
echo $allowed[array_rand($allowed)];
This way you're removing the excluded numbers from the selection set, and nullifying the need for a loop :)
Produce an array of the allowed numbers. Find out the number in this array. Select one of those randomly.

array_rand() array to string?

I have an array, such like:
$hex = array("0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f");
I want to return 6 random elements as a string (eg. 1a3564):
$random_color = array_rand($hex,6);
I thought imploding $random_color would do the trick:
echo implode($random_color);
But array_rand() stores positions of elements in parent array, not this array elements, so I get something like:
259111213 instead of 259bcd.
I know this does exactly what I want:
echo $hex[$random_color[0]];
echo $hex[$random_color[1]];
echo $hex[$random_color[2]];
echo $hex[$random_color[3]];
echo $hex[$random_color[4]];
echo $hex[$random_color[5]];
But:
is there any way to store array elements within array_rand()? Why it stores elements' positions instead of elements in the first place?
what's the best way to do what I want to achieve?
why does array_rand() NEVER choose a letter as the first element, and almost never as the second/third (99% of generated colors look like 11111a 12345c 123456)?
Random colors should be generated in simplier way:
printf('%02x%02x%02x',mt_rand(0,255),mt_rand(0,255),mt_rand(0,255));
or
printf('%06x',mt_rand(0,16777215));
If you need to save color to variable, use sprintf instead of printf
Since the items are all different, you can turn them into keys rather than values, then use array_rand on the result:
implode('', array_rand(array_flip($hex), 6));
However, there may be a better way of achieving your overall goal. For example, if the overall goal allows for repetitions of digits, simply generate a random number from 0 through 0xFFFFFF and convert to a hex string:
dechex(mt_rand(0, 0xFFFFFF));
Why it stores elements' positions instead of elements in the first place?
From the manual page:
This is done so that you can pick random keys as well as values out of the array.
why does array_rand() NEVER choose a letter as the first element, and almost never as the second/third (99% of generated colors look like 11111a 12345c 123456)?
array_rand uses rand (php_rand, in the C source). Depending on your system, php_rand is rand, random or lrand48. rand is a particularly poor random number generator.
array_rand() returns the keys of the randomly picked elements (see manual, section Return Values).
In order for it to work as expected, use array_flip() to retrieve the keys:
$random_color = array_rand(array_flip($hex), 6);
As for the "strange" results where there are almost no letters first elements, IDEOne and my server seem to reproduce these findings. A local machine running in my office (still running Debian etch / PHP 5.2.9) seems to disagree and evenly distribute elements from $hex... Seems to be a PHP version thing?
you are close try this:
$hex = array("0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f");
shuffle($hex);
echo sub_str(implode('',$hex),0,6);
If you don't need to maintain the order of the $hex array, you could substitute this with shuffle(). Something like this (codepad example):
<?php
$hex = array("0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f");
shuffle($hex);
echo implode(array_slice($hex, 0, 6));
If you just want a random string of hex digits, you could also do something like
substr(md5(time()),-6);
or
substr(md5(uniqid()),-6);
You would get similar results without having to mess with the array.
is there any way to store array elements within array_rand()? Why it
stores elements' positions instead of elements in the first place?
According to array_rand documentation, it returns the array 'keys', not the 'values'. Since your array is not an associative array, the keys are numbers. You'd need to do (untested):
$result = "";
$random_color = array_rand($hex, 6);
foreach ($random_color as $randomIndex) {
$result = $result . $hex[$randomIndex];
}
Don't use array shuffle or array_rand because elements cannot repeat with that approach. That's not what you are trying to do.
what's the best way to do what I want to achieve?
If you want to generate a random color, you can use:
$color = '';
while(strlen($c) < 6) {
$color .= sprintf("%02X", mt_rand(0, 255));
}
why does array_rand() NEVER choose a letter as the first element, and
almost never as the second/third (99% of generated colors look like
11111a 12345c 123456)?
You may need to initialize the random numbers generator, but this is just a guess (see Timur's comment to this answer).
mt_srand((double)microtime()*1000000);

Collect Lowest Numbers Algorithm

I'm looking for an algorithm (or PHP code, I suppose) to end up with the 10 lowest numbers from a group of numbers. I was thinking of making a ten item array, checking to see if the current number is lower than one of the numbers in the array, and if so, finding the highest number in the array and replacing it with the current number.
However, I'm planning on finding the lowest 10 numbers from thousands, and was thinking there might be a faster way to do it. I plan on implementing this in PHP, so any native PHP functions are usable.
Sort the array and use the ten first/last entries.
Honestly: sorting an array with a thousand entries costs less time than it takes you to blink.
What you're looking for is called a selection algorithm. The Wikipedia page on the subject has a few subsections in the selecting k smallest or largest elements section. When the list is large enough, you can beat the time required for the naive "sort the whole list and choose the first 10" algorithm.
Naive approach is to just sort the input. It's likely fast enough, so just try it and profile it before doing anything more complicated.
Potentially faster approach: Linearly search the input, but keep the output array sorted to make it easier to determine if the next input belongs in the array or not. Pseudocode:
output[0-9] = input[0-9];
sort(output);
for i=10..n-1
if input[i] < output[9]
insert(input[i])
where insert(x) will find the right spot (binary search) and do the appropriate shifting.
But seriously, just try the naive approach first.
Where are you getting this group of numbers?
If your List of numbers is already in an array you could simply do a sort(), and then a array_slice() to get the first 10.
I doesn't matter much for a small array, but as it gets larger a fast and easy way to increase processing speed is to take advantage of array key indexing, which for 1 mill. rows will use about 40% of the time. Example:
// sorting array values
$numbers = array();
for($i = 0; $i < 1000000; ++$i)
{
$numbers[$i] = rand(1, 999999);
}
$start = microtime(true);
sort($numbers);
$res = array_slice($numbers, 0, 10, true);
echo microtime(true) - $start . "\n";
// 2.6612658500671
print_r($res);
unset($numbers, $res, $start);
// sorting array keys
$numbers = array();
for($i = 0; $i < 1000000; ++$i)
{
$numbers[rand(1, 999999)] = $i;
}
$start = microtime(true);
ksort($numbers);
$res = array_keys(array_slice($numbers, 0, 10, true));
echo microtime(true) - $start . "\n";
// 0.9651210308075
print_r($res);
But if the array data is from a database the fastest is probably to just sort it there:
SELECT number_column FROM table_with_numbers ORDER BY number_column LIMIT 10
Create a sorted set (TreeSet in Java, I don't know about PHP), and add the first 10 numbers. Now iterate over the rest of the numbers Iterate over all your numbers, add the new one, then remove the biggest number from the set.
This algorithm is O(n) if n >> 10.
I would use a heap with 10 elements and the highest number at the root of the tree. Then start at the beginning of the list of numbers:
If the heap has less than 10 elements: add the number to the list
Otherwise, if the number is smaller than the highest number in the heap, remove the highest number in the heap, and then add the current number to the list
Otherwise, ignore it.
You will end up with the 10 lowest numbers in the heap. If you are using an array as the heap data structure, then you can just use the array directly.
(alternatively: you can slice out the first 10 elements, and heapify them instead of using the first step above, which will be slightly faster).
However, as other people have noted, for 1000 elements, just sort the list and take the first 10 elements.

Categories