Related
I need to generate three different random numbers without repeating, Three different random numbers need to be within 10 of the answer
for the sample IQ Question: 4,6 ,9,6,14,6,... Ans:19
A: random numbers
B: random numbers
C: random numbers
D: random numbers
one of them is the answer
I am now using the following code but sometimes the numbers are repeated, I have tried shuffle But which one is really random cannot satisfy random numbers need to be within 10 of the answer
$ans = $row['answer'];
$a = rand (1,10);
$a1 = rand($ans-$a ,$ans+$a);
$a2 = rand($ans-$a ,$ans+$a);
$a3 = rand($ans-$a ,$ans+$a);
As shown in previous answers (e.g. Generating random numbers without repeats, Simple random variable php without repeat, Generating random numbers without repeats) you can use shuffle to randomise a range, and then pick three items using array_slice.
The difference in your case is how you define the range:
Rather than 1 to 10, you want $ans - 10 to $ans + 10
You want to exclude the right answer
One way to build that is as two ranges: lower limit up to but not including right answer, and right answer + 1 up to upper limit.
function generate_wrong_answers($rightAnswer) {
// Generate all wrong guesses from 10 below to 10 above,
// but miss out the correct answer
$wrongAnswers = array_merge(
range($rightAnswer - 10, $rightAnswer - 1),
range($rightAnswer + 1, $rightAnswer + 10)
);
// Randomise
shuffle($wrongAnswers);
// Pick 3
return array_slice($wrongAnswers, 0, 3);
}
Firstly, I'm still a beginner to PHP so my terminology may be a bit wrong - please let me know and I'll amend the question.
Task:
I have a function which I'm looking to test to see how long it takes to run at large scale. I need to pass it data in the following format:
$data = [
[ 'A', 'B', 'C', 'D' ],
[ 'C', 'B' ],
[ 'C', 'B' ],
];
As you can see, the number of items in an array can vary - although they are drawn from an overall set (range of integers or letters).
For my testing purposes, I'd like to be able to change the number of items in each nested array.
I also need to be able to change how many arrays are created.
Example tests I'd like to perform
e.g.
Run one test with a small number of arrays, but a large amount of
data within each.
Run a second test with a large number of arrays, but
a small amount of data in each
A third with huge numbers of items
and arrays.
The story so far
I was Googling and know I could use range() to create an array that count sequentially (or with a certain step). But I have to set the upper and lower bounds for each array.
I figure I could use a do.. while loop to add X number of arrays within $data, but I'm not sure how I can vary the amount of data within each array.
For the function to work, I need there to be either a letter or integer repeated. In other words: I couldn't have the first array count from 1-10, the next 11-21. It's as if all the data is drawn from the pool of integers 1-10,000,000.
Bonus points if the data can be randomized in order in each array.
Really appreciate any guidance and pointers on what to use / research - I'm sure this is a totally n00b question.
Many thanks in advance.
Generate a random range:
range(mt_rand(0, 100), mt_rand(101, 1000))
Generate an array of letters from a range (65 = A, 90 = Z):
array_map('chr', range(65, 90))
Generate a random order:
$data = range(..);
shuffle($data);
Take a random slice of an array:
$data = range(..);
$data = array_slice($data, mt_rand(0, count($data) - 1), mt_rand(1, count($data)));
Generate arrays of random length:
for ($i = 0, $length = mt_rand(0, 100); $i < $length; $i++) {
$data[] = ..;
}
You can nest two of those to generate randomly long arrays of randomly long arrays.
Now combine all these techniques as needed to spit out the kind of test data you want.
I had an interesting discussion with my good developer friends. I wanted to create a random sequence of given array values but with maximum fragmentation, without any detectable patterns. This so called maximum randomness would be practically always identical for any unique sequence.
Example input array:
array(1, 2, 3, 4, 5);
Example result of a standard rand() function:
array(2, 3, 1, 5, 4);
What I don't like in the output above are the sequence values like "2, 3" and "5, 4", It's not fragmented enough.
Expecting result would/could be:
array(3, 5, 1, 4, 2);
So my question; is there any known formula to calculate the maximum randomness or for better choice of words, maximum fragmentation?
So what are you talking about, not randomization, it is sorting. The result of randomization should not depend on order of the initial data.
By fragmentation in this case it is necessary to understand the differences between the array before sorting and after. But it must be evaluated differently depending on the task. For example, one can evaluate the difference between the positions of the elements or it's order.
Sorting example.
<?
// it must be uksort() function with sequence formula, but for me easier do like this
$array = array(1, 2, 3, 4, 5);
uk_sort($array);
function uk_sort(&$array) {
for($i=0;$i<count($array);$i++) {
if($i%2==0) {
$even[] = $array[$i];
} else {
$odd[] = $array[$i];
}
}
$even[] = array_shift($even);
rsort($odd);
$array = array_merge($even, $odd);
}
print_r($array);
?>
Array
(
[0] => 3
[1] => 5
[2] => 1
[3] => 4
[4] => 2
)
You could split the list into two (or more) collections, shuffle those THEN mix them in order?
array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
array(1, 2, 3, 4, 5);
array(6, 7, 8, 9, 10);
array(2, 3, 1, 5, 4);
array(8, 7, 10, 9, 6);
array(2, 8, 3, 7, 1, 10, 5, 9, 4, 6)
This would give you a fairly high fragmentation but not the maximum.
I suspect to get the maximum would require a LOT more work.
Assuming the fragmentation is defined as the sum of the absolute differences of successive values, the maximum fragmentation sequence is not unique -- the reverse sequence will always have the exact same fragmentation and there're many more options, e.g. all the following orderings will have a fragmentation of 11, which is maximal for this array: (3,1,5,2,4), (3,2,5,1,4), (2,5,1,4,3), (2,4,1,5,3), (4,1,5,2,3), (4,2,5,1,3), (3,5,1,4,2), (3,4,1,5,2). There're yet more symmetries if one incorporates the difference between the last and the first element, too.
If one seeks to identify a particular maximum fragmentation sequence, e.g. the one "without a noticeable pattern", the latter notion has to be formalized and a search performed, which, I suspect, would be costly from the computational point of view, unless the objective can be formalized so as to permit efficient decoding. I suspect that for all practical purposes a good heuristic would suffice, e.g. inserting elements into an array one by one (greedy fashion) so as to maximize the gain in fragmentation on each step.
If the elements of the array are not numbers but some entities with a defined distance for each pair, however, the problem does become equivalent to the traveling salesman problem, as user802500 pointed out.
I think this sounds like a traveling salesman type problem, with the "distance" being the difference between two chosen entries, except your goal would be to maximize the total distance rather than minimize it.
I don't actually know a ton about the topic, but here's what I think I know:
There are algorithms for the traveling salesman problem, but they can be quite slow in the limit (they're NP-hard). On the other hand, there are good approximations, and simple cases may be solvable, though it will still be a non-trivial algorithm.
Depending on how important it is to have maximum fragmentation, you could also try a naive method: given an element, choose the next element so that it's quite distant from the given element. Then choose a next element, and so on. The problem with this is that your early choices can back you into a corner. So this won't work if fragmentation is quite important to you.
[2,5,1,3,4] // the first three choices force us to not fragment the last two
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.
I'm working in a LAMP environment, so PHP is the language; at least i can use python.
As the title said i have two unordered integer arrays.
$array_A = array(13, 4, 59, 38, 9, 69, 72, 93, 1, 3, 5)
$array_B = array(29, 72, 21, 3, 6)
I want to know how many integers these array have in common; in the example as you see the result is 2. I'm not interested in what integers are in common, like (72, 3).
I need a faster method than take every element of array B and check if it's in array A ( O(nxm) )
Arrays can be sorted through asort or with sql ordering (they came from a sql result).
An idea that came to me is to create a 'vector' for every array where the integer is a position who gets value 1 and integers not present get 0.
So, for array A (starting at pos 1)
(1, 0, 1, 1, 1, 0, 0, 0, 1, 0, ...)
Same for array B
(0, 0, 1, 0, 0, 1, ...)
And then compare this two vectors with one cycle. The problem is that in this way the vector length is about 400k.
Depending on your data (size) you might want to use array_intersect_key() instead of array_intersect(). Apparently the implementation of array_intersect (testing php 5.3) does not use any optimization/caching/whatsoever but loops through the array and compares the values one by one for each element in array A. The hashtable lookup is incredibly faster than that.
<?php
function timefn($fn) {
static $timer = array();
if ( is_null($fn) ) {
return $timer;
}
$x = range(1, 120000);
$y = range(2, 100000);
foreach($y as $k=>$v) { if (0===$k%3) unset($y[$k]); }
$s = microtime(true);
$fn($x, $y);
$e = microtime(true);
#$timer[ $fn ] += $e - $s;
}
function fnIntersect($x, $y) {
$z = count(array_intersect($x,$y));
}
function fnFlip($x, $y) {
$x = array_flip($x);
$y = array_flip($y);
$z = count(array_intersect_key($x, $y));
}
for ($i=0; $i<3; $i++) {
timefn( 'fnIntersect' );
timefn( 'fnFlip' );
}
print_r(timefn(null));
printsArray
(
[fnIntersect] => 11.271192073822
[fnFlip] => 0.54442691802979
)which means the array_flip/intersect_key method is ~20 times faster on my notebook.
(as usual: this is an ad hoc test. If you spot an error, tell me ...I'm expecting that ;-) )
I don't know a great deal about PHP so you may get a more specific answer from others, but I'd like to present a more language-agnostic approach.
By checking every element in A against every element in B, it is indeed O(n2) [I'll assume the arrays are of identical length here to simplify the equations but the same reasoning will hold for arrays of differing lengths].
If you were to sort the data in both arrays, you could reduce the time complexity to O(n log n) or similar, depending on the algorithm chosen.
But you need to keep in mind that the complexity only really becomes important for larger data sets. If those two arrays you gave were typical of the size, I would say don't sort it, just use the "compare everything with everything" method - sorting won't give you enough of an advantage over that. Arrays of 50 elements would still only give you 2,500 iterations (whether that's acceptable to PHP, I don't know, it would certainly be water off a duck's back for C and other compiled languages).
And before anyone jumps in and states that you should plan for larger data sets just in case, that's YAGNI, as unnecessary as premature optimization. You may never need it in which case you've wasted time that would have been better spent elsewhere. The time to implement that would be when it became a problem (that's my opinion of course, others may disagree).
If the data sets really are large enough to make the O(n2) unworkable, I think sorting then walking through the arrays in parallel is probably your best bet.
One other possibility is if the range of numbers is not too big - then your proposed solution of a vector of booleans is quite workable since that would be O(n), walking both arrays to populate the vector followed by comparisons of fixed locations within the two vectors. But I'm assuming your range is too large or you wouldn't have already mentioned the 400K requirement. But again, the size of the data sets will dictate whether or not that's worth doing.
The simplest way would be:
count(array_intersect($array_A, $array_B));
if I understand what you're after.
Should be fast.
If both arrays came from SQL, could you not write an SQL query with an inner join on the 2 sets of data to get your result?
You want the array_intersect() function. From there you can count the result. Don't worry about speed until you know you have a problem. The built-in function execute much faster than anything you'll be able to write in PHP.
I have written a PHP extension that provides functions for efficient set operations like union, intersection, binary search, etc. Internal data layout is an ordinary int32_t array stored in a PHP string. Operations are based on merge algorithms.
Example:
// Create two intarrays
$a = intarray_create_from_array(array(1, 2, 3));
$b = intarray_create_from_array(array(3, 4, 5));
// Get a union of them
$u = intarray_union($a, $b);
// Dump to screen
intarray_dump($u);
It's available here: https://github.com/tuner/intarray