I'm trying to find each missing number in an array like the following.
Array (
[0] => 1 [1] => 2 [2] => 3 [3] => 4 [4] => 5 [5] => 6 [6] => 7 [7] => 8
[8] => 9 [9] => 10 [10] => 11 [11] => 12 [12] => 13 [13] => 14 [14] => 15
[15] => 16 [16] => 17 [17] => 18 [18] => 19 [19] => 20 [20] => 21 [21] => 22
[22] => 23 [23] => 24 [24] => 25 [25] => 26 [26] => 27 [27] => 28 [28] => 29
[29] => 30 [30] => 31 [31] => 32 [32] => 33 [33] => 34 [34] => 35 [35] => 36
[36] => 37 [37] => 38 [38] => 39 [39] => 40 [40] => 41 [41] => 42 [42] => 43
[43] => 44 [44] => 45 [45] => 46 [46] => 47 [47] => 48 [48] => 49 [49] => 50
[50] => 51 [51] => 52 [52] => 53 [53] => 54 [54] => 55 [55] => 56 [56] => 57
[57] => 58 [58] => 59 [59] => 60 [60] => 61 [61] => 62 [62] => 63 [63] => 64
[64] => 67 [65] => 68 [66] => 69
)
The numbers 65,66 are missing in this particular array.
My question how do I figure out which numbers are missing with the help of PHP. Specifically what I need to find out is the lowest missing number.
Why: Because then I can assign that number to a member as an id.
You can make use of array_diff and range functions as:
// given array. 3 and 6 are missing.
$arr1 = array(1,2,4,5,7);
// construct a new array:1,2....max(given array).
$arr2 = range(1,max($arr1));
// use array_diff to get the missing elements
$missing = array_diff($arr2,$arr1); // (3,6)
I'm assuming the number is the element, not the key, of the array. I'm also assuming that the numbers start from 1, not 0.
$Expected = 1;
foreach ($InputArray as $Key => $Number)
{
if ($Expected != $Number)
{
break;
}
$Expected++;
}
echo $Number;
For big sorted arrays of unique numbers, you can binary search the array for either the lowest or highest unused number. Cost=Log2N. Example: 65536 items can be searched in 16 loops since
if ( arr[hi] - arr[lo] > hi - lo )
... there are unused numbers in that range ...
So (I don't know PHP, but it can be translated...):
lo = first entry index
hi = last entry index
if ( arr[hi] - arr[lo] == hi - lo )
return arr[hi]+1; // no gaps so return highest + 1
do
{
mid = (lo + hi) / 2;
if ( arr[mid] - arr[lo] > mid - lo ) // there is a gap in the bottom half somewhere
hi = mid; // search the bottom half
else
lo = mid; // search the top half
} while ( hi > lo + 1 ); // search until 2 left
return arr[lo]+1;
If given input is not in sorted order and size of input is very large then we can use following logic in any programming language:
Algorithm
bring smaller chunk into memory from large input
initialize three variables say min = 0, max = 0 and missingIds = []
scan smaller chunked input from left to right
if scannedValue found in missingIds
then,
pop scannedValue from missingIds
go to next value;
If scanned value is near to min
then,
find all the missing numbers between scannedValue and min, push into missingIds
min = scannedValue;
Else if scanned value is near to max
then,
find all the missing numbers between scannedValue and max, push into missingIds
max = scannedValue;
repeat above steps until large input scanned from left to right
Example in PHP
<?php
$largeInput = [40,41,42,43,44,45,1,2,3,4,5,6,7,8,9,10,11,12,13,14,35,36,37,38,39,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,67,68,69,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34];
$missingIds = [];
$min = 0;
$max = 0;
$chunkSize = 10;
$chunkNo = 0;
$currentInput = array_slice($largeInput, $chunkNo, $chunkSize);
while(count($currentInput) > 0) {
foreach($currentInput as $id) {
if(in_array($id,$missingIds)) {
$missingIds = array_diff($missingIds,[$id]);
continue;
}
if($id <= $min) {
$distMin = $min - $id;
if($distMin > 2) {
$tempArr = range($id+1,$min-1);
$missingIds = array_merge($missingIds, $tempArr);
$tempArr = [];
} else if ($distMin > 1) {
$tempArr = [$id+1];
$missingIds = array_merge($missingIds, $tempArr);
$tempArr = [];
}
$min = $id;
} else if ($id >= $max){
$distMax = $id - $max;
if($distMax > 2) {
$tempArr = range($max+1,$id-1);
$missingIds = array_merge($missingIds, $tempArr);
$tempArr = [];
} else if ($distMax > 1) {
$tempArr = [$max+1];
$missingIds = array_merge($missingIds, $tempArr);
$tempArr = [];
}
$max = $id;
}
}
$chunkNo++;
$currentInput = array_slice($largeInput, $chunkNo, $chunkSize);
}
print_r($missingIds);
//$idArrayMissing = array([0] => 1, [1] => 2, [2] => 4, [3] => 5, [4] => 6, [5] => 7);
$idArrayMissing = array(1, 2, 4, 5, 6, 7);
//$idArrayFull = array([0] => 1, [1] => 2, [2] => 3, [3] => 4, [4] => 5, [5] => 6);
$idArrayFull = array(1, 2, 3, 4, 5, 6);
function gap($arr)
{
while (list($k, $v) = each($arr))
if ($k != ($v-1))
return $k;
return -1;
}
print "ok:" . gap($idArrayMissing) . "<br/>\n";
print "full:" . gap($idArrayFull) . "<br/>\n";
The return of the gap function can be 2 values:
-1 could indicate that the array has been traversed and there are no free slots or
$k+1 which could indicate that the first free slot is on the end of the array.
It can also be done easily by using in_array() function like this:
// lets say $InputArray has all the data
// lets declare a variable which we will search inside the $InputArray array and lets initialize it with either 0 or 1 or with the minimum value found inside $InputArray
$start_counting = 1;
$max_value = count($InputArray);
if (!(in_array($start_counting, $InputArray)))
{
echo "Value: ".$start_counting." is missing!"."<br>" ;
}
else{
if($start_counting <= $max_value -1)
{$start_counting++;}
}
else if($start_counting > $max_value -1)
{
echo "All missing numbers printed!"
}
}
Related
Suppose an array is give:
$given_array=Array(
[0] => 30
[1] => 45
[2] => 60
[3] => 75
[4] => 90
[5] => 105
[6] => 120
[7] => 135)
A number is given example: 195
Number until 195 needs to be inserted with a difference of 15
So resulting array is:
Array(
[0] => 30
[1] => 45
[2] => 60
[3] => 75
[4] => 90
[5] => 105
[6] => 120
[7] => 135
[8] => 150
[9] => 165
[10] => 180
[11] => 195)
Need to know the best approach to do so time required is least.
So far i have tried:
$given_num=195;
if((given_num-$given_array[count($given_array)-1])!=15 && count($given_array)>0){
while(($given_array[count($given_array)-1]+15)<=given_num){
$given_array[]=$given_array[count($given_array)-1]+15;
}
}
Results are correct but not time feasible
I see that the goal is to have an array with subsequent numbers divisible by 15. Unless you really have to reuse the old array (I wouldn't know why), I
would suggest creating a new array with range():
$given_array = range($given_array[0], 195, 15);
Haven't tried yours and not sure whats wrong with it regarding speed but try this.
<?php
$given_array=[30, 45, 60, 75, 90, 105, 120, 135];
$newNumber = 195;
$count = floor(($newNumber - $given_array[count($given_array)-1]) / 15);
for($i=0; $i<$count; $i++) {
array_push($given_array, $given_array[count($given_array)-1]+15);
}
print_r($given_array);
example: https://3v4l.org/vPiAW
I would say:
$given_num = 195;
$last = end($given_array);
while ($given_num > $last) {
$last = min($last + 15, $given_num);
$given_array[] = $last;
}
But the range-version is quite nice =)
Another short solution using end function:
while (($last = end($given_array)) < 195) $given_array[] = $last+15;
// now, $given_array contains all the needed items
I am trying to calculate the winning order of golfers when they are tied in a competition.
These golf competitions are using the "stableford" points scoring system, where you score points per hole with the highest points winning. Compared to normal golf "stroke play" where the lowest score wins (though this also has the countback system, only calculating the lowest score in the event of a tie...)
The rules are to use a "countback". i.e., if scores are tied after 9 holes, the best placed of the ties is the best score from the last 8 holes. then 7 holes, etc.
The best I can come up with is 2 arrays.
An array with all the players who tied in a given round. ($ties)
One which has the full score data in (referencing the database playerid) for all 9 holes. ($tie_perhole)
I loop through array 1, pulling data from array 2 and using the following formula to create a temporary array with the highest score:
$max = array_keys($array,max($array));
If $max only has 1 item, this player is the highest scorer. the loop through the first array is "by reference", so on the next iteration of the loop, his playerid is now longer in the array, thus ignored. this continues until there is only 1 playerid left in the first array.
However, it only works if a single player wins in each iteration. The scenario that doesn't work is if a sub-set of players tie on any iterations / countbacks.
I think my problem is the current structure I have will need the original $ties array to become split, and then to continue to iterate through the split arrays in the same way...
As an example...
The $ties array is as follows:
Array
(
[18] => Array
(
[0] => 77
[1] => 79
[2] => 76
[3] => 78
)
)
The $tie_perhole (score data) array is as follows:
Array
(
[18] => Array
(
[77] => Array
(
[9] => 18
[8] => 16
[7] => 14
[6] => 12
[5] => 10
[4] => 8
[3] => 6
[2] => 4
[1] => 2
)
[79] => Array
(
[9] => 18
[8] => 17
[7] => 15
[6] => 14
[5] => 11
[4] => 9
[3] => 7
[2] => 5
[1] => 3
)
[76] => Array
(
[9] => 18
[8] => 16
[7] => 14
[6] => 12
[5] => 10
[4] => 8
[3] => 6
[2] => 4
[1] => 2
)
[78] => Array
(
[9] => 18
[8] => 17
[7] => 15
[6] => 13
[5] => 11
[4] => 9
[3] => 7
[2] => 5
[1] => 3
)
)
)
So in this competition, player's 78 and 79 score highest on the 8th hole countback (17pts), so 1st and 2nd should be between them. Player 79 should then be 1st on the 6th hole countback (14pts, compared to 13pts). The same should occur for 3rd and 4th place with the 2 remaining other players.
There are other scenarios that can occur here, in that within a competition, there will likely be many groups of players (of different amounts) on different tied points through the leaderboard.
Also note, there will be some players on the leaderboard who are NOT tied and stay in their current outright position.
The basics of the working code I have is:
foreach ($ties as $comparekey => &$compareval) {
$tie_loop = 0;
for ($m = 9; $m >= 1; $m--) {
$compare = array();
foreach ($compareval as $tie) {
$compare[$tie] = $tie_perhole[$comparekey][$tie][$m];
}
$row = array_keys($compare,max($compare));
if (count($row) == 1) {
$indexties = array_search($row[0], $ties[$comparekey]);
unset($ties[$comparekey][$indexties]);
// Now update this "winners" finishing position in a sorted array
// This is a multidimensional array too, with custom function...
$indexresults = searchForId($row[0], $comp_results_arr);
$comp_results_arr[$indexresults][position] = $tie_loop;
$tie_loop++;
}
// I think I need conditions here to filter if a subset of players tie
// Other than count($row) == 1
// And possibly splitting out into multiple $ties arrays for each thread...
if (empty($ties[$comparekey])) {
break;
}
}
}
usort($comp_results_arr, 'compare_posn_asc');
foreach($comp_results_arr as $row) {
//echo an HTML table...
}
Thanks in advance for any helpful insights, tips, thoughts, etc...
Robert Cathay asked for more scenarios. So here is another...
The leaderboard actually has more entrants (player 26 had a bad round...), but the code i need help with is only bothered about the ties within the leaderboard.
Summary leaderboard:
Points Player
21 48
21 75
20 73
20 1
13 26
This example produces a $tie_perhole array of:
Array
(
[21] => Array
(
[75] => Array
(
[9] => 21
[8] => 19
[7] => 16
[6] => 14
[5] => 12
[4] => 9
[3] => 7
[2] => 5
[1] => 3
)
[48] => Array
(
[9] => 21
[8] => 19
[7] => 16
[6] => 13
[5] => 11
[4] => 9
[3] => 8
[2] => 5
[1] => 3
)
)
[20] => Array
(
[73] => Array
(
[9] => 20
[8] => 18
[7] => 16
[6] => 13
[5] => 11
[4] => 8
[3] => 6
[2] => 5
[1] => 3
)
[1] => Array
(
[9] => 20
[8] => 17
[7] => 16
[6] => 14
[5] => 12
[4] => 9
[3] => 7
[2] => 4
[1] => 2
)
)
)
In this example, the array shows that players 75 and 48 scored 21 points that player 75 will eventually win on the 6th hole countback (14pts compared to 13pts) and player 48 is 2nd. In the next tied group, players 73 and 1 scored 20 points, and player 73 will win this group on the 8th hole countback and finishes 3rd (18 pts compared to 17 pts), with player 1 in 4th. player 26 is then 5th.
Note, the $tie_loop is added to another array to calculate the 1st to 5th place finishing positions, so that is working.
Hopefully that is enough to help.
Ok, so I don't understand golf at all... hahaha BUT! I think I got the gist of this problem, so heres my solution.
<?php
/**
* Author : Carlos Alaniz
* Email : Carlos.glvn1993#gmail.com
* Porpuse : Stackoverflow example
* Date : Aug/04/2015
**/
$golfers = [
"A" => [1,5,9,1,1,2,3,4,9],
"B" => [2,6,4,2,4,4,1,9,3],
"C" => [3,4,9,8,1,1,5,1,3],
"D" => [1,5,1,1,1,5,4,5,8]
];
//Iterate over scores.
function get_winners(&$golfers, $hole = 9){
$positions = array(); // The score numer is the key!
foreach ($golfers as $golfer=>$score ) { // Get key and value
$score_sub = array_slice($score,0,$hole); // Get the scores subset, first iteration is always all holes
$total_score = (string)array_sum($score_sub); // Get the key
if(!isset($positions[$total_score])){
$positions[$total_score] = array(); // Make array
}
$positions[$total_score][] = $golfer; // Add Golpher to score.
}
ksort($positions, SORT_NUMERIC); // Sort based on key, low -> high
return array(end($positions), key($positions)); // The last shall be first
}
//Recursion is Awsome
function getWinner(&$golfers, $hole = 9){
if ($hole == 0) return;
$winner = get_winners($golfers,$hole); // Get all ties, if any.
if(count($winner[0]) > 1){ // If theirs ties, filter again!
$sub_golfers =
array_intersect_key($golfers,
array_flip($winner[0])); // Only the Worthy Shall Pass.
$winner = getWinner($sub_golfers,$hole - 1); // And again...
}
return $winner; // We got a winner, unless they really tie...
}
echo "<pre>";
print_R(getWinner($golfers));
echo "</pre>";
Ok... Now ill explain my method...
Since we need to know the highest score and it might be ties, it makes no sense to me to maintain all that in separate arrays, instead I just reversed the
golfer => scores
to
Tota_score => golfers
That way when we can sort the array by key and obtain all the golfers with the highest score.
Now total_score is the total sum of a subset of the holes scores array. So... the first time this function runs, it will add all 9 holes, in this case theres 3 golfers that end up with the same score.
Array
(
[0] => Array
(
[0] => A
[1] => B
[2] => C
)
[1] => 35
)
Since the total count of golfers is not 1 and we are still in the 9th hole, we run this again, but this time only against those 3 golfers and the current hole - 1, so we are only adding up to the 8th hole this time.
Array
(
[0] => Array
(
[0] => B
[1] => C
)
[1] => 32
)
We had another tie.... this process will continue until we reach the final hole, or a winner.
Array
(
[0] => Array
(
[0] => C
)
[1] => 31
)
EDIT
<?php
/**
* Author : Carlos Alaniz
* Email : Carlos.glvn1993#gmail.com
* Porpuse : Stackoverflow example
**/
$golfers = [
"77" => [2,4,6,8,10,12,14,16,18],
"79" => [3,5,7,9,11,14,15,17,18],
"76" => [2,4,6,8,10,12,14,16,18],
"78" => [3,5,7,9,11,13,15,17,18]
];
//Iterate over scores.
function get_winners(&$golfers, $hole = 9){
$positions = array(); // The score numer is the key!
foreach ($golfers as $golfer => $score) { // Get key and value
//$score_sub = array_slice($score,0,$hole); // Get the scores subset, first iteration is always all holes
$total_score = (string)$score[$hole-1]; // Get the key
if(!isset($positions[$total_score])){
$positions[$total_score] = array(); // Make array
}
$positions[$total_score][] = $golfer; // Add Golpher to score.
}
ksort($positions, SORT_NUMERIC); // Sort based on key, low -> high
return [
"winner"=> end($positions),
"score" => key($positions),
"tiebreaker_hole" => [
"hole"=>$hole,
"score"=> key($positions)],
]; // The last shall be first
}
//Recursion is Awsome
function getWinner(&$golfers, $hole = 9){
if ($hole == 0) return;
$highest = get_winners($golfers,$hole); // Get all ties, if any.
$winner = $highest;
if(count($winner["winner"]) > 1){ // If theirs ties, filter again!
$sub_golfers =
array_intersect_key($golfers,
array_flip($winner["winner"])); // Only the Worthy Shall Pass.
$winner = getWinner($sub_golfers,$hole - 1); // And again...
}
$winner["score"] = $highest["score"];
return $winner; // We got a winner, unless they really tie...
}
echo "<pre>";
print_R(getWinner($golfers));
echo "</pre>";
Result:
Array
(
[winner] => Array
(
[0] => 79
)
[score] => 18
[tiebreaker_hole] => Array
(
[hole] => 6
[score] => 14
)
)
I have this array:
Array
(
[1] => 20130701 4 4 3060 1
[2] => 20130702 270 757 13812810 4
[3] => 20130703 5 123 3894971 2
[4] => 20130704 290 478 5119617 1
[5] => 20130705 88 98 189791 2
[6] => 20130708 9 73 564627 1
[7] => 20130722 6102 11992 41974701 1
[8] => 20130723 6397 11021 40522224 1
[9] => 20130725 4644 9336 49167728 2
[10] => 20130726 4891 10157 33516844 3
[11] => 20130727 123 319 2538226 3
[12] => 20130728 451 801 1078705 2
[13] => 20130729 13609 30407 95551827 5
[14] => 20130730 6354 17550 272794650 158
[15] => 20130731 6270 18456 269468599 174
)
I'm trying to change the output in order to show it in a chart, do i change it into a json:
foreach ($day as $key => $value) {
$value = explode(" ", $value) ;
$day[$key] = $value ;
$charts[] = array(substr($value[0],0,4).'-'.substr($value[0],4,2).'-'.substr($value[0],6,2),$value[4]) ;
}
$charts = json_encode($charts, JSON_NUMERIC_CHECK) ;
But it displays me this :
[["2013-07-01","1\r"],["2013-07-02","4\r"],["2013-07-03","2\r"],["2013-07-04","1\r"],["2013-07-05","2\r"],["2013-07-08","1\r"],["2013-07-22","1\r"],["2013-07-23","1\r"],["2013-07-25","2\r"],["2013-07-26","3\r"],["2013-07-27","3\r"],["2013-07-28","2\r"],["2013-07-29","5\r"],["2013-07-30","158\r"],["2013-07-31","174\r"]]
why \r does show? any way I can prevent this ?
try
$charts[] = array(substr($value[0],0,4).'-'.substr($value[0],4,2).'-'.substr($value[0],6,2),substr($value[4],0, -1)) ;
You have return characters at the end of your array
[3] => 20130703 5 123 3894971 2\r
They are not visible because \n = new line \r returns the pointer to the beginning of the line.
Your best bet is to use trim() on every element:
foreach ($day as $key => $value) {
$value = explode(" ", trim($value));
$day[$key] = trim($value) ;
$charts[] = array(trim(substr($value[0],0,4).'-'.substr($value[0],4,2).'-'.substr($value[0],6,2),$value[4])) ;
}
It's even better on numbers to use intval(), which ensures datatype to be integer and removes blankspaces, returns, ... too.
I wrote a FFT (Fast Fourier Transform) module for PHP recently. When I tried to test it, It always throws an error that the array $this->reverseTable has some index not defined. I got no clue of how to solve this problem.
Here's the PHP code:
<?php
class FourierTransform {
public $bufferSize;
public $sampleRate;
public $bandwidth;
public $spectrum = array();
public $real = array();
public $imag = array();
public $peakBand = 0;
public $peak = 0;
public function __construct($bufferSize,$sampleRate){
$this->bufferSize = $bufferSize;
$this->sampleRate = $sampleRate;
$this->bandwidth = 2 / $bufferSize * $sampleRate / 2;
}
public function getBandFrequency($index){
return $this->bandwidth * $index + $this->bandwidth / 2;
}
public function calculateSpectrum(){
$bSi = 2 / $this->bufferSize;
for($i = 0,$N = $this->bufferSize/2; $i < $N; $i++){
$rval = $this->real[$i];
$ival = $this->imag[$i];
$mag = $bSi * sqrt($rval * $rval + $ival * $ival);
if($mag > $this->peak){
$this->peakBand = $i;
$this->peak = $mag;
}
$this->spectrum[$i] = $mag;
}
}
}
class FFT extends FourierTransform {
public $reverseTable = array();
public $sinTable = array();
public $cosTable = array();
public function __construct($bufferSize,$sampleRate){
parent::__construct($bufferSize,$sampleRate);
$limit = 1;
$bit = $bufferSize >> 1;
while($limit < $bufferSize){
for($i = 0; $i < $limit; $i++){
$this->reverseTable[$i + $limit] = $this->reverseTable[$i] + $bit;
}
$limit = $limit << 1;
$bit = $bit >> 1;
}
for($i = 0; $i < $bufferSize; $i++){
$this->sinTable[$i] = sin(-M_PI / $i);
$this->cosTable[$i] = cos(-M_PI / $i);
}
}
public function foward($buffer){
$k = floor(log($this->bufferSize,2));
if(pow(2,$k) !== $this->bufferSize) throw new Exception('Invalid buffer size, must be a power of 2.');
if($this->bufferSize !== count($buffer)) throw new Exception('Supplied buffer is not the same size as defined FFT.');
$halfSize = 1;
for($i = 0; $i < $this->bufferSize; $i++){
$this->real[$i] = $buffer[$this->reverseTable[$i]];
$this->imag[$i] = 0;
}
while($halfSize < $this->bufferSize){
$phaseShiftReal = $this->cosTable[$halfSize];
$phaseShiftImag = $this->sinTable[$halfSize];
$currentPhaseShiftReal = 1;
$currentPhaseShiftImag = 0;
for($fftStep = 0; $fftStep < $halfSize; $fftStep++){
while($fftStep < $this->bufferSize){
$off = $fftStep + $halfSize;
$tr = ($currentPhaseShiftReal * $this->real[$off]) - ($currentPhaseShiftImag * $this->imag[$off]);
$ti = ($currentPhaseShiftReal * $this->imag[$off]) + ($currentPhaseShiftImag * $this->real[$off]);
$this->real[$off] = $this->real[$fftStep] - $tr;
$this->imag[$off] = $this->imag[$fftStep] - $ti;
$this->real[$fftStep] += $tr;
$this->imag[$fftStep] += $ti;
$fftStep += $halfSize << 1;
}
$tmpReal = $currentPhaseShiftReal;
$currentPhaseShiftReal = ($tmpReal * $phaseShiftReal) - ($currentPhaseShiftImag * $phaseShiftImag);
$currentPhaseShiftImag = ($tmpReal * $phaseShiftImag) + ($currentPhaseShiftImag * $phaseShiftReal);
}
$halfSize = $halfSize << 1;
}
$this->calculateSpectrum();
}
}
?>
The test sample is a sine wave at 440Hz.
When I tried to run the code, it throws this error
Notice: Undefined offset: 0 in C:\Program Files
(x86)\EasyPHP-12.1\www\fft.php on line 48
continuously.
The array that has problem has data like this:
Array
(
[1] => 512
[2] => 256
[3] => 768
[4] => 128
[5] => 640
[6] => 384
[7] => 896
[8] => 64
[9] => 576
[10] => 320
[11] => 832
[12] => 192
[13] => 704
[14] => 448
[15] => 960
[16] => 32
[17] => 544
[18] => 288
[19] => 800
[20] => 160
[21] => 672
[22] => 416
[23] => 928
[24] => 96
[25] => 608
[26] => 352
[27] => 864
[28] => 224
[29] => 736
[30] => 480
[31] => 992
[32] => 16
[33] => 528
[34] => 272
[35] => 784
[36] => 144
[37] => 656
[38] => 400
[39] => 912
[40] => 80
[41] => 592
[42] => 336
[43] => 848
[44] => 208
[45] => 720
...
[978] => 303
[979] => 815
[980] => 175
[981] => 687
[982] => 431
[983] => 943
[984] => 111
[985] => 623
[986] => 367
[987] => 879
[988] => 239
[989] => 751
[990] => 495
[991] => 1007
[992] => 31
[993] => 543
[994] => 287
[995] => 799
[996] => 159
[997] => 671
[998] => 415
[999] => 927
[1000] => 95
[1001] => 607
[1002] => 351
[1003] => 863
[1004] => 223
[1005] => 735
[1006] => 479
[1007] => 991
[1008] => 63
[1009] => 575
[1010] => 319
[1011] => 831
[1012] => 191
[1013] => 703
[1014] => 447
[1015] => 959
[1016] => 127
[1017] => 639
[1018] => 383
[1019] => 895
[1020] => 255
[1021] => 767
[1022] => 511
[1023] => 1023
)
Edit: The previous problem is solved but now another problem is raised. At function forward() it throws an uncaught exception Invalid buffer size, must be a power of 2. Even if the buffer size is right.
Any help will be appreciated.
Assuming that this is the whole class, I presume that the issue lies on this line inside your FFT constructor:
$this->reverseTable[$i + $limit] = $this->reverseTable[$i] + $bit;
From what I can tell you declare reverseTable as an array, but this line is the only place in the class where any elements are added to that array, so the fact that you're setting the reverseTable[$i+$limit] element using a never-defined reverseTable[$i] value is going to give you problems in the first first iteration of that while loop when it tries to use the undefined index $i (reverseTable[$i]). You'll have to give reverseTable[0] a value before you enter that loop.
Although you didn't provide where the line was, my guess is it has something to do with this line:
$this->reverseTable[$i + $limit] = $this->reverseTable[$i] + $bit;
This is in your constructor, and this bit especially looks wrong $this->reverseTable[$i] + $bit;. You are asking for the value from the reverseTable array, but this key is not initialized anywhere in the constructor.
I am not sure how to fix this, as it is a logic error on your part.
I need to generate random UNIQUE numbers within a range, how can I do that? I can generate random number by
generator:
$arr = [];
$x = rand($min, $max);
$len = count($arr);
$flag = 0;
for($i = 0; $i < $len; $i++)
{
if ($flag === 1)
goto generator;
if ($x === $arr[$i])
$flag = 1;
}
$arr[$index] = $x;
$index++;
goto generator;
I know this code is bad, so I need a better optimized code of my version !
help !
example:
if i need to generate 3 numbers within 1 to 15 they should be like 5, 9, 1 but not 3,1,2 [with in 1 - 3 (numbers i want to generate) ]
Array with range of numbers at random order:
$numbers = range(1, 20);
shuffle($numbers);
Wrapped function:
function UniqueRandomNumbersWithinRange($min, $max, $quantity) {
$numbers = range($min, $max);
shuffle($numbers);
return array_slice($numbers, 0, $quantity);
}
Example:
<?php
print_r( UniqueRandomNumbersWithinRange(0,25,5) );
?>
Result:
Array
(
[0] => 14
[1] => 16
[2] => 17
[3] => 20
[4] => 1
)
$len = 10; // total number of numbers
$min = 100; // minimum
$max = 999; // maximum
$range = []; // initialize array
foreach (range(0, $len - 1) as $i) {
while(in_array($num = mt_rand($min, $max), $range));
$range[] = $num;
}
print_r($range);
I was interested to see how the accepted answer stacks up against mine. It's useful to note, a hybrid of both may be advantageous; in fact a function that conditionally uses one or the other depending on certain values:
# The accepted answer
function randRange1($min, $max, $count)
{
$numbers = range($min, $max);
shuffle($numbers);
return array_slice($numbers, 0, $count);
}
# My answer
function randRange2($min, $max, $count)
{
$i = 0;
$range = array();
while ($i++ < $count) {
while(in_array($num = mt_rand($min, $max), $range));
$range[] = $num;
}
return $range;
}
echo 'randRange1: small range, high count' . PHP_EOL;
$time = microtime(true);
randRange1(0, 9999, 5000);
echo (microtime(true) - $time) . PHP_EOL . PHP_EOL;
echo 'randRange2: small range, high count' . PHP_EOL;
$time = microtime(true);
randRange2(0, 9999, 5000);
echo (microtime(true) - $time) . PHP_EOL . PHP_EOL;
echo 'randRange1: high range, small count' . PHP_EOL;
$time = microtime(true);
randRange1(0, 999999, 6);
echo (microtime(true) - $time) . PHP_EOL . PHP_EOL;
echo 'randRange2: high range, small count' . PHP_EOL;
$time = microtime(true);
randRange2(0, 999999, 6);
echo (microtime(true) - $time) . PHP_EOL . PHP_EOL;
The results:
randRange1: small range, high count
0.019910097122192
randRange2: small range, high count
1.5043621063232
randRange1: high range, small count
2.4722430706024
randRange2: high range, small count
0.0001051425933837
If you're using a smaller range and a higher count of returned values, the accepted answer is certainly optimal; however as I had expected, larger ranges and smaller counts will take much longer with the accepted answer, as it must store every possible value in range. You even run the risk of blowing PHP's memory cap. A hybrid that evaluates the ratio between range and count, and conditionally chooses the generator would be the best of both worlds.
The idea consists to use the keys, when a value is already present in the array keys, the array size stays the same:
function getDistinctRandomNumbers ($nb, $min, $max) {
if ($max - $min + 1 < $nb)
return false; // or throw an exception
$res = array();
do {
$res[mt_rand($min, $max)] = 1;
} while (count($res) !== $nb);
return array_keys($res);
}
Pro: This way avoids the use of in_array and doesn't generate a huge array. So, it is fast and preserves a lot of memory.
Cons: when the rate (range/quantity) decreases, the speed decreases too (but stays correct). For a same rate, relative speed increases with the range size.(*)
(*) I understand that fact since there are more free integers to select (in particular for the first steps), but if somebody has the mathematical formula that describes this behaviour, I am interested by, don't hesitate.
Conclusion: The best "general" function seems to be a mix between this function and #Anne function that is more efficient with a little rate. This function should switch between the two ways when a certain quantity is needed and a rate (range/quantity) is reached. So the complexity/time of the test to know that, must be taken in account.
If you want to generate 100 numbers that are random, but each number appearing only once, a good way would be to generate an array with the numbers in order, then shuffle it.
Something like this:
$arr = array();
for ($i=1;$i<=101;$i++) {
$arr[] = $i;
}
shuffle($arr);
print_r($arr);
Output will look something like this:
Array
(
[0] => 16
[1] => 93
[2] => 46
[3] => 55
[4] => 18
[5] => 63
[6] => 19
[7] => 91
[8] => 99
[9] => 14
[10] => 45
[11] => 68
[12] => 61
[13] => 86
[14] => 64
[15] => 17
[16] => 27
[17] => 35
[18] => 87
[19] => 10
[20] => 95
[21] => 43
[22] => 51
[23] => 92
[24] => 22
[25] => 58
[26] => 71
[27] => 13
[28] => 66
[29] => 53
[30] => 49
[31] => 78
[32] => 69
[33] => 1
[34] => 42
[35] => 47
[36] => 26
[37] => 76
[38] => 70
[39] => 100
[40] => 57
[41] => 2
[42] => 23
[43] => 15
[44] => 96
[45] => 48
[46] => 29
[47] => 81
[48] => 4
[49] => 33
[50] => 79
[51] => 84
[52] => 80
[53] => 101
[54] => 88
[55] => 90
[56] => 56
[57] => 62
[58] => 65
[59] => 38
[60] => 67
[61] => 74
[62] => 37
[63] => 60
[64] => 21
[65] => 89
[66] => 3
[67] => 32
[68] => 25
[69] => 52
[70] => 50
[71] => 20
[72] => 12
[73] => 7
[74] => 54
[75] => 36
[76] => 28
[77] => 97
[78] => 94
[79] => 41
[80] => 72
[81] => 40
[82] => 83
[83] => 30
[84] => 34
[85] => 39
[86] => 6
[87] => 98
[88] => 8
[89] => 24
[90] => 5
[91] => 11
[92] => 73
[93] => 44
[94] => 85
[95] => 82
[96] => 75
[97] => 31
[98] => 77
[99] => 9
[100] => 59
)
If you need 5 random numbers between 1 and 15, you should do:
var_dump(getRandomNumbers(1, 15, 5));
function getRandomNumbers($min, $max, $count)
{
if ($count > (($max - $min)+1))
{
return false;
}
$values = range($min, $max);
shuffle($values);
return array_slice($values,0, $count);
}
It will return false if you specify a count value larger then the possible range of numbers.
You can try next code:
function unique_randoms($min, $max, $count) {
$arr = array();
while(count($arr) < $count){
$tmp =mt_rand($min,$max);
if(!in_array($tmp, $arr)){
$arr[] = $tmp;
}
}
return $arr;
}
Get a random number. Is it stored in the array already? If not, store it. If so, then go get another random number and repeat.
When creating an application where I needed to generate 30,000 unique numbers within a larger range, I was able to cut down processing time from 25 seconds to 1.5 seconds using this method.
The idea is that PHP is much faster at generating random numbers than it is at checking the existence of items in an array - that is why using a while(in_array) loop can be slow.
$count = 0;
$collectNumbers = [];
while ($count < 30000) {
for ($i = 0; $i < 60000; $i++) {
$rand = mt_rand(1, 100000);
$collectNumbers[] = $rand;
}
$unique = array_unique($collectNumbers);
$count = count($unique);
}
$finalArray = array_slice($unique, 0, 30000);
This will return 30,000 unique numbers extremely quickly. Using an iteration value that is double the amount of numbers you need to generate can increase the likelihood of unique numbers the first iteration... but regardless of how many iterations it takes, this will produce a result faster than checking your array for repeated numbers in a loop.
This probably will solve your problem:
<?php print_r(array_rand(range(1,50), 5)); ?>
I guess this is probably a non issue for most but I tried to solve it. I think I have a pretty decent solution. In case anyone else stumbles upon this issue.
function randomNums($gen, $trim, $low, $high)
{
$results_to_gen = $gen;
$low_range = $low;
$high_range = $high;
$trim_results_to= $trim;
$items = array();
$results = range( 1, $results_to_gen);
$i = 1;
foreach($results as $result)
{
$result = mt_rand( $low_range, $high_range);
$items[] = $result;
}
$unique = array_unique( $items, SORT_NUMERIC);
$countem = count( $unique);
$unique_counted = $countem -$trim_results_to;
$sum = array_slice($unique, $unique_counted);
foreach ($sum as $key)
{
$output = $i++.' : '.$key.'<br>';
echo $output;
}
}
randomNums(1100, 1000 ,890000, 899999);
This is how I would do it.
$randnum1 = mt_rand(1,20);
$nomatch = 0;
while($nomatch == 0){
$randnum2 = mt_rand(1,20);
if($randnum2 != $randnum1){
$nomatch = 1;
}
}
$nomatch = 0;
while($nomatch == 0){
$randnum3 = mt_rand(1,20);
if(($randnum3 != $randnum1)and($randnum3 != $randnum2)){
$nomatch = 1;
}
}
Then you can echo the results to check
echo "Random numbers are " . $randnum1 . "," . $randnum2 . ", and " . $randnum3 . "\n";
The "shuffle" method has a MAJOR FALW. When the numbers are big, shuffle 3 billion indexs will instantly CAUSE 500 error. Here comes a best solution for really big numbers.
function getRandomNumbers($min, $max, $total) {
$temp_arr = array();
while(sizeof($temp_arr) < $total) $temp_arr[rand($min, $max)] = true;
return $temp_arr;
}
Say I want to get 10 unique random numbers from 1 billion to 4 billion.
$random_numbers = getRandomNumbers(1000000000,4000000000,10);
PS: Execution time: 0.027 microseconds
Simply use this function and pass the count of number you want to generate
Code:
function randomFix($length)
{
$random= "";
srand((double)microtime()*1000000);
$data = "AbcDE123IJKLMN67QRSTUVWXYZ";
$data .= "aBCdefghijklmn123opq45rs67tuv89wxyz";
$data .= "0FGH45OP89";
for($i = 0; $i < $length; $i++)
{
$random .= substr($data, (rand()%(strlen($data))), 1);
}
return $random;}
The best way to generate the unique random number is
<?php
echo md5(uniqid(mt_rand(), true).microtime(true));
?>