I'm trying to understand how sorting an array in random order works. So, I found the following code:
var as = ["max","jack","sam"];
var s = as.sort(func);
function func(a, b) {
return 0.5 - Math.random();
}
console.log(s);
my main question is why they use 0.5 not another number?
and how it really works
You used
var as = ["max","jack","sam"];
var s = as.sort(func);
function func(a, b) {
return 0.5 - Math.random();
}
console.log(s);
And here the most important thing is as.sort(func).
func(a,b) will return value in range of [-0.5,0.5].
Because this function return 0.5 - Math.random() and Math.random() will return the float value which is in range of [0,1].
So that your func will return value in range of [-0.5,0.5].
And this mean that sort order will be set increase or decrease.
this is random.
So your result will be random
var as = ["max","jack","sam"];
var s = as.sort(func);
function func(a, b) {
return Math.random();
}
console.log(s);
var as = ["max","jack","sam"];
var s = as.sort(func);
function func(a, b) {
return 0 - Math.random();
}
console.log(s);
var as = ["max","jack","sam"];
var s = as.sort(func);
function func(a, b) {
return 0.5 - Math.random();
}
console.log(s);
Math.random() returns a number between 0 and 1 (exclusive). We're using 0.5 because it is the mean value.
Array.sort() sorts the parameters based on the return value. So, 0.5 - Math.random() will yield either positive or negative value with equal probability. Hence, it will sort the parameters randomly.
How it really works
If the return value of Array.sort() is positive, then the index of the
first parameter will be higher than that of the second.
If it is negative, then the index of the second parameter will be
higher than that of the first.
And, if it is 0, then do nothing.
Math.random() return random value between 0 to 1 (0 is included but 1 is excluded).
So 0.5 act as mid point. If use use value like greater than 1 or less 0 than it will always be either true or false.
So for this reason 0.5 is used.
You can read more here about Math.random()
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random
Let's understand it bit more with examples
var as = ["max","jack","sam"];
var s = as.sort(func);
function func(a, b) {
return 0.5 - Math.random();
}
console.log(s);
This is what you get when you use value greater than 1
var as = ["max","jack","sam"];
var s = as.sort(func);
function func(a, b) {
return 1 - Math.random();
}
console.log(s);
This is what happens when you use value less than 0
var as = ["max","jack","sam"];
var s = as.sort(func);
function func(a, b) {
return -1 - Math.random();
}
console.log(s);
P.S :-
Try printing output from all the above condition you will see that last two condition will always return either true or false from function. so you will not get a random sorting.
Now talk about any value from 0 to 0.99 you can use any value but 0.5 will serve your purpose best.Because it's a middle point you're most likely to get best answer.
If you just want to nudge the elements near their starting positions in a random way, sure, use sort with random, but in most cases, that's not what you want. You want to thoroughly shuffle an array, completely randomize the position of every element. And for that random in the built-in sort function is a terrible practice, because it is biased towards the initial state, meaning that the elements in the "shuffled" array will tend to stay near their positions (those that were near the beginning have the high probability of staying near the beginning, etc...). The bigger the size the array grows, the less it gets shuffled.
Here is the proof: Is it correct to use JavaScript Array.sort() method for shuffling?
And here is the function for shuffling arrays I use most of the time. It thoroughly randomizes the position of every element.
function shuffle(arr) { // randomly rearanges the items in an array
const result = [];
for (let i = arr.length-1; i >= 0; i--) {
// picks an integer between 0 and i:
const r = Math.floor(Math.random()*(i+1)); // NOTE: use a better RNG if cryptographic security is needed
// inserts the arr[i] element in the r-th free space in the shuffled array:
for(let j = 0, k = 0; j <= arr.length-1; j++) {
if(result[j] === undefined) {
if(k === r) {
result[j] = arr[i]; // NOTE: if array contains objects, this doesn't clone them! Use a better clone function instead, if that is needed.
break;
}
k++;
}
}
}
return result;
}
Math.random returns a number between 0 and 1.
Sorting function use the return value x as the following :
x == 0 : Same value, can order "how it wants"
x < 0 : the first object is less than the second one, therefore its index in the sorted array will be less than the other's
x > 0 same as x < 0 but the other way around
Since Math.random returns a number between 0 and 1 and we want to also get negative numbers, we must subtract some value.
Here 0.5 - Math.random() would give a number between 0.5 and -0.5
If you call the sort method with a function parameter is called several times. This function should accept two parameters (let's call the first A and the second B) Each time it should return a value:
Less than zero, if A < B
Equal to zero, if A = B
Greater the zero, if A > B
So in this example we need random return values that evenly distribute negative and positive values. Since Math.random() returns a value between 0 and 1, 0.5 - Math.random() will return values between -0.5 and 0.5, which meets the requirements.
Shortest Form (Using Lambda Expression):
To answer the question "How sorting of an array in random order works", as others have mentioned, the Array.sort() function can take a function as parameter.
Syntax:
Array.sort([sort_by_function()])
The inner sort_by_function() accepts two parameters (e.g.: x & y) and with use of Math.random() returns a value between -0.5 to 0.5, it returns:
Negative number (-0.5 to -0.1), if x < y
Zero (0), if x = y Positive
Positive number (0.1 to 0.5), if x > y
Remember, if you don't pass in anything to the outer Array.sort() function, it simply rearranges/sorts the elements in Ascending order, if however, you pass in a function (as argument), then it behaves based on what the inner sort_by_function() returns, as it swaps EACH Element of the given array (by swapping pair of two elements at-a-time) essentially, this swapping is decided based on what the inner sort_by_function() returned.
To achieve random-sort order the Array.sort() function will rearrange/sort each pair of elements as below, for a:
Negative value: swap in ascending order,
Zero: no change,
Positive value: swap in descending order.
Example:
arr.sort(function(x,y){return Math.random() - 0.5});
As no one mentioned about the use of the short Lambda expression, here is an example on how you can shorten the inner parameter-function by use of the Lambda expression as below:
arr.sort(() => Math.random() - 0.5);
Related
UPDATE AT THE BOTTOM OF THE POST!
This is the first part of a program that will eventually make SVG star polygons.
Only star polygons that can be made in one go, I.e. like a Pentagram, NOT like a Hexagram that can only be made with at least 2 shapes I.e. 2 inverted and overlapping triangles.
I'm almost finished with this. Everything seems to be working well and I'm getting the out put I want except there's an empty array item in every other array produced for some reason.
In this part
I'm printing to the console (for testing) an object with items named with numbers that represent the number of points / sides of a regular polygon. Within each item is an array with the lower half of all the non factoring numbers of that item (number) I.e. an array of numbers that when the number (item name) is divided by them, it will return a fraction.
E.g. Object
starPolygons{'5': 2, '7': 3, 2, '8': 3, '9': 4, 2, …}
(Representation of: Pentagon: Heptagon: Octagon: Nonagon: …)
What "qty_test" functions does
The points variable (= 8 for example) is sent to a function (qty_test) which is used to find the number of divisors I need to test and inside it is divided by 2. If the result is a fraction, it will return the result rounded back, and if its even, it will return the result - 1.
//8 has more divisors to cycle through -so its a better example!
//In the real program, it will be 5.
let points = 8;
let starPolygons = {};
E.g. qty_test
point (=8) ()=> n /= 2 (=4)
if n - n(rounded-back) = 0?
true returns (n -1) and false returns n(rounded-back)
function qty_test(n) {
n /= 2;
let divisorQTY = n - Math.floor(n) !== 0;
return divisorQTY ? Math.floor(n) : (n - 1);
};
What divisor_test functions does
This function uses the number returned from the previous function (n) to set a for loop that tests every cycle if n is not a factor of the value of the points variable. I.e. points divided by n returns a fraction and if it returns true, meaning a fraction was produced n`s value is indexed in an array and decreaces by 1 (--n).
E.g. divisor_test
n(=8) / 2 = 4 << 2 will be ignored.
n(=8) / 3 = 2.666... << 3 will be collected
function divisor_test(n) {
let nonFactors = [];
n = qty_test(n);
for (let index = 0; index <= n; index++) {
let quotient = (points / n) - Math.floor(points / n) !== 0;
quotient ? nonFactors[index] = n-- : --n;
};
return nonFactors;
};
The program cycles through 5 - 360 and indexes an object with numbers (5-360) and array list of their lower half non factor numbers.
while (points <= 360) {
nonFactors = divisor_test(points);
let testArray = nonFactors.length;
if (testArray) starPolygons[String(points)] = nonFactors;
points++;
};
console.log(starPolygons);
AS YOU CAN SEE IN THIS IMAGE. THE PATTERN OF EMPTY ARRAY INDEXES / ITEMS
UPDATE: I NOTICED THE PATTERN OF ARRAYS WITH THE EMPTY SLOTS HAS AN INTERESTING QUALITY TO IT. This is so cool and so confusing as to what causes this...
During the Iteration you are forcing the array to add an empty item.
So, the empty object appears when the array has only two items in it and you are trying to nonFactors[3] = n--;
and thats what causes the issue.
So a more simplified version of the for loop with the solution will be
for (let index = 0; index <= n; index++) {
let quotient = (points / n) - Math.floor(points / n) !== 0;
if(quotient){
if(index > nonFactors.length){
nonFactors[index - 1] = n--
}else{
nonFactors[index] = n--
}
}else{
n = n -1;
}
};
I solved my problem
There's an answer here that already explains what causes the problem and also gives a working solution by Nadav Hury (upvote his answer. I bet his answer generally works better in more situations)! So I will just post my own version of a solution.
for (let index = 0; n >= 2; index++) {
let quotient = (points / n) - Math.floor(points / n) !== 0;
if (quotient) nonFactors[index] = n--;
else --n, --index;
};
The culprit is that in the line with checking the quotient
quotient ? nonFactors[index] = n-- : --n;
you added setting the value only for the case when it is present that is equal to true but you didn't add to the case when it is false correct solution is:
quotient ? nonFactors[index] = n-- : nonFactors[index] = --n;.
I entered a coding test where one of the questions was this: given an array A of integers of any length, and then two numbers N and Z, say whether there are Z (distinct) numbers in A such as their sum is N.
So for example (in the format A N Z):
for [1,2,3] 5 2 the answer is YES because 2+3=5
for [1,2,3] 6 2 the answer is NO because there are no two numbers in A that can be added to make 6
My solution (below) first enumerates every (unordered) combination of Z numbers in A, then sums it, and then searches for N in the list of sums.
Although this solution works fine (passed all test cases, with no timeout), I was told the score was too low for me to continue in the test.
So the question is, what can be improved?
An obvious optimization would be to calculate the sum of each combination immediately, and then stop when a match with N is found; but since I didn't run into time issues I don't think this is the problem. What is the better, more elegant/efficient solution?
function main(a, n, z) {
var spacea = [], // array of unordered combinations of z integers from a
space = [], // array of unique sums of combinations from spacea
res=0; // result (1 or 0)
// produce combination
spacea = combo(a,z);
// put unique sums in space
spacea.forEach(function(arr) {
var s = arr.reduce(function(a,b) {
return a+b;
});
if (space.indexOf(s)<0) space.push(s);
});
// is n in space?
res = space.indexOf(n) === -1 ? "NO" :"YES";
return res;
}
// produces combinations (outputs array of arrays)
function combo(a, z) {
var i,
r = [],
head,
right;
if (z > a.length || z <= 0) {
// do nothing, r is already set to []
}
else if (a.length === z) {
r = [a];
}
else if (1 === z) {
// r = array of array of values from a
a.forEach(function(e) {
r.push([e]);
});
}
else { // by virtue of above tests, z>1 and z<a.length
for (i=0; i<a.length-z+1; i++) {
head = a.slice(i, i+1);
right = combo(a.slice(i+1), z-1);
right.forEach(function(e) {
r.push(head.concat(e));
});
}
}
return r;
}
This is a variation of the subset sum problem, which can be solved with Dynamic Programming for more efficient solution.
The main difference here, is you have an extra restriction - the number of elements that must be used. This extra restriction can be handled by adding another variable (dimension) - the number of already used elements.
The recursive formulas (which you will build the DP solution from) should be:
D(0,0,0) = true
D(i,k,x) = false if i < 0 or k < 0
D(i,k,x) = D(i-1, k, x) OR D(i-1, k-1, x - arr[i])
In the above, D(i,k,x) is true if and only if there is a solution that uses k exactly k numbers, from the first i elements, and sums to x.
Complexity of this solution is O(n*N*Z) where n - number of elements in the array, N - number of distinct elements you can use, Z - target sum.
I am doing a challenge on Coderbyte and I would be grateful for any advice on my question:
The challenge given to me:
"Using the JavaScript language, have the function ArrayAdditionI(arr)
take the array of numbers stored in arr and return the string true if
any combination of numbers in the array can be added up to equal the
largest number in the array, otherwise return the string false.
For example: if arr contains [4, 6, 23, 10, 1, 3] the output should
return true because 4 + 6 + 10 + 3 = 23. The array will not be empty,
will not contain all the same elements, and may contain negative numbers. "
The way I attempted to solve it: http://jsfiddle.net/reLsg0fg/
function ArrayAdditionI(arr){
var newArr=arr.sort(); // sorted from smallest to largest.
var largestNum=newArr.slice(-1); // Gets the last number, which would be the largest.
var loopArr=arr.sort().pop(); // Takes out the largest number for adding later.
var result=0;
for(var i=0; i<loopArr.length; i++){ // loops through all numbers.
if(result/largestNum !== 1){ //when you divide a number by itself it will be 1.
result+=loopArr[i]; // keep adding each number until get largest number.
}else if(result === largestNum){
return true;
}
}
return false;
}
// TESTS
console.log("-----");
console.log(ArrayAdditionI([4,6,23,10,1,3]));
console.log(ArrayAdditionI([5,7,16,1,2]));
console.log(ArrayAdditionI([3,5,-1,8,12]));
I'm supposed to get true, false, true. But I get false, false, false as if something is wrong within my loop. JSFiddle: http://jsfiddle.net/reLsg0fg/
I would appreciate any suggestions. Thank you ^^
Sort Array using
arr.sort(function (a, b) { return a - b })
I have tried to solve this problem with a for loop but I missed the fact that the challenge
is not asking that all numbers need to add up to equal the largest num, but it is also possible to
add up to the largest num if we take some numbers out. Thus I decided to solve with recursion.
Tips:
* The Math.max.apply() method takes an array and returns the largest number. Note that it usually works on strings as Math.max().
* the sort() method can take a parameter to further expand it's purpose. Usually it only
sorts strings, but to sort numbers we include a function that finds which number is bigger.
* First get the largest number.
* Sort the array and remove the largest number to be used for recursion later.
* Create a recursion function that checks if the numbers add up to the largest number, and if not, check that if some numbers in array are subtracted from the largest num they are equal to the largest number.
function ArrayAdditionI(array){
var largestNum = Math.max.apply(0, array); // gets the largest number in array.
array.sort(function(a,b){ return a-b;}).pop(); // sorts array and removes last(largest) number.
function recursionCheck(arr, sum){
// the base case when array empty.
if(arr.length === 0){
return sum === 0;
}
var arrBeginNum=arr[0];
// for every recursion take away one number(the first one in this case).
arr = arr.slice(1);
// first check if numbers sum up to largest num if not, check if removing numbers adds up to largest num.
return recursionCheck(arr, sum) || recursionCheck(arr, sum - arrBeginNum);
}
// recursion needs to be called for it to start.
return recursionCheck(array, largestNum);
}
// TESTS
console.log("-----");
console.log(ArrayAdditionI([1,2,3,5,4])); ==> true
console.log(ArrayAdditionI([21,10,12,9,2])); ==> true
console.log(ArrayAdditionI([4,6,23,10,1,3])); ===> true
console.log(ArrayAdditionI([5,7,16,1,2])); ===> false
console.log(ArrayAdditionI([3,5,-1,8,12])); ===> true
This might not be the complete solution yet, but here are the JavaScript-Problems:
largestNum was an array in you algorithm
.sort() was not working
function ArrayAdditionI(arr){
var largestNum = Math.max.apply(0, arr); // Gets the last number, which would be the largest.
arr.sort(function(a, b){return a-b})
arr.pop(); // Takes out the largest number for adding later.
var result=0;
Also use if(result !== largestNum) {, Division is expensive and might have unexpected results with floating-point numbers.
Thats it for your JavaScript. But I am pretty sure the Algorithm is wrong - but I think this is up to you
Note that the example [4, 6, 23, 10, 1, 3] => 4 + 6 + 10 + 3 = 23 is not just adding up the lowest to the biggest value to try and match it.
A possible example of a solution for the problem.
How this works:
First sort all items descending
Shift the first element to largest
Call the recursive function y with the reduced array, the largest value and a variable which holds an empty array for the successfully added items.
The recursive function works basically in two parts
Test if the remaining sum is zero, if so the result is achieved and return true, which finished the function.
If not iterate through the array and
Make a copy from the array
Get the value from the position with splice
Test, if the value is smaller or equal the remaining sum and the result of the call of y with the shorted array, sum minus value and a new array with the used items and the acual item.
If true return true and finish the function.
If not finished before return false.
function x(array) {
function y(a, s, result) {
var aa, i, v;
if (s === 0) {
document.write('<pre>result: ' + JSON.stringify(result, 0, 4) + '</pre>');
return true;
}
for (i = 0; i < a.length; i++) {
aa = a.slice();
v = aa.splice(i, 1)[0];
if (v <= s && y(aa, s - v, result.concat(v))) {
return true;
}
}
return false;
}
var largest,
r = [];
array.sort(function (a, b) { return b - a; });
largest = array.shift();
document.write('largest value: ' + largest + '<br>');
return y(array, largest, r);
}
document.write(x([4, 6, 23, 10, 1, 3]) + '<hr>');
document.write(x([5, 7, 16, 1, 2]) + '<hr>');
document.write(x([3, 5, -1, 8, 12]));
Thanks #mar
Here is a version in Kotlin if someone needs
private fun returnResult(arr: Array<Int>): Boolean {
arr.sort()
val largestNumber = arr.last()
val arrWithoutLargest = arr.dropLast(1).toTypedArray()
return recursionCheck(arrWithoutLargest, largestNumber)
}
private fun recursionCheck(arr: Array<Int>, sum:Int): Boolean {
if (arr.isEmpty()) return sum == 0
val arrBeginNum = arr[0]
val arr2 = arr.drop(1).toTypedArray()
return recursionCheck(arr2, sum) || recursionCheck(arr2, sum - arrBeginNum)
}
Let's say I have the following code:
arr = [0.1,0.5,0.2,0.2]; //The percentages (or decimals) we want to distribute them over.
value = 100; //The amount of things we have to distribute
arr2 = [0,0,0,0] //Where we want how many of each value to go
To find out how to equally distribute a hundred over the array is simple, it's a case of:
0.1 * 100 = 10
0.5 * 100 = 50
...
Or doing it using a for loop:
for (var i = 0; j < arr.length; i++) {
arr2[i] = arr[i] * value;
}
However, let's say each counter is an object and thus has to be whole. How can I equally (as much as I can) distribute them on a different value. Let's say the value becomes 12.
0.1 * 12 = 1.2
0.5 * 12 = 6
...
How do I deal with the decimal when I need it to be whole? Rounding means that I could potentially not have the 12 pieces needed.
A correct algorithm would -
Take an input/iterate through an array of values (for this example we'll be using the array defined above.
Turn it into a set of whole values, which added together equal the value (which will equal 100 for this)
Output an array of values which, for this example it will look something like [10,50,20,20] (these add up to 100, which is what we need to add them up to and also are all whole).
If any value is not whole, it should make it whole so the whole array still adds up to the value needed (100).
TL;DR dealing with decimals when distributing values over an array and attempting to turn them into an integer
Note - Should this be posted on a different stackoverflow website, my need is programming, but the actual question will likely be solved using a mathematics. Also, I had no idea how to word this question, which makes googling incredibly difficult. If I've missed something incredibly obvious, please tell me.
You should round all values as you assign them using a rounding that is known to uniformly distribute the rounding. Finally, the last value will be assigned differently to round the sum up to 1.
Let's start slowly or things get very confused. First, let's see how to assign the last value to have a total of the desired value.
// we will need this later on
sum = 0;
// assign all values but the last
for (i = 0; i < output.length - 1; i++)
{
output[i] = input[i] * total;
sum += output[i];
}
// last value must honor the total constraint
output[i] = total - sum;
That last line needs some explanation. The i will be one more than the last allowed int the for(..) loop, so it will be:
output.length - 1 // last index
The value we assign will be so that the sum of all elements is equal to total. We already computed the sum in a single-pass during the assignment of the values, and thus don't need to iterated over the elements a second time to determine it.
Next, we will approach the rounding problem. Let's simplify the above code so that it uses a function on which we will elaborate shortly after:
sum = 0;
for (i = 0; i < output.length - 1; i++)
{
output[i] = u(input[i], total);
sum += output[i];
}
output[i] = total - sum;
As you can see, nothing has changed but the introduction of the u() function. Let's concentrate on this now.
There are several approaches on how to implement u().
DEFINITION
u(c, total) ::= c * total
By this definition you get the same as above. It is precise and good, but as you have asked before, you want the values to be natural numbers (e.G. integers). So while for real numbers this is already perfect, for natural numbers we have to round it. Let's suppose we use the simple rounding rule for integers:
[ 0.0, 0.5 [ => round down
[ 0.5, 1.0 [ => round up
This is achieved with:
function u(c, total)
{
return Math.round(c * total);
}
When you are unlucky, you may round up (or round down) so much values that the last value correction will not be enough to honor the total constraint and generally, all value will seem to be off by too much. This is a well known problem of which exists a multi-dimensional solution to draw lines in 2D and 3D space which is called the Bresenham algorithm.
To make things easy I'll show you here how to implement it in 1 dimension (which is your case).
Let's first discuss a term: the remainder. This is what is left after you have rounded your numbers. It is computed as the difference between what you wish and what you really have:
DEFINITION
WISH ::= c * total
HAVE ::= Math.round(WISH)
REMAINDER ::= WISH - HAVE
Now think about it. The remained is like the piece of paper that you discard when you cut out a shape from a sheet. That remaining paper is still there but you throw it away. Instead of this, just add it to the next cut-out so it is not wasted:
WISH ::= c * total + REMAINDER_FROM_PREVIOUS_STEP
HAVE ::= Math.round(WISH)
REMAINDER ::= WISH - HAVE
This way you keep the error and carry it over to the next partition in your computation. This is called amortizing the error.
Here is an amortized implementation of u():
// amortized is defined outside u because we need to have a side-effect across calls of u
function u(c, total)
{
var real, natural;
real = c * total + amortized;
natural = Math.round(real);
amortized = real - natural;
return natural;
}
On your own accord you may wish to have another rounding rule as Math.floor() or Math.ceil().
What I would advise you to do is to use Math.floor(), because it is proven to be correct with the total constraint. When you use Math.round() you will have smoother amortization, but you risk to not have the last value positive. You might end up with something like this:
[ 1, 0, 0, 1, 1, 0, -1 ]
Only when ALL VALUES are far away from 0 you can be confident that the last value will also be positive. So, for the general case the Bresenham algoritm would use flooring, resulting in this last implementation:
function u(c, total)
{
var real, natural;
real = c * total + amortized;
natural = Math.floor(real); // just to be on the safe side
amortized = real - natural;
return natural;
}
sum = 0;
amortized = 0;
for (i = 0; i < output.length - 1; i++)
{
output[i] = u(input[i], total);
sum += output[i];
}
output[i] = total - sum;
Obviously, input and output array must have the same size and the values in input must be a paritition (sum up to 1).
This kind of algorithm is very common for probabilistical and statistical computations.
Alternate implementation - it remembers a pointer to the biggest rounded value and when the sum differs of 100, increment or decrement value at this position.
const items = [1, 2, 3, 5];
const total = items.reduce((total, x) => total + x, 0);
let result = [], sum = 0, biggestRound = 0, roundPointer;
items.forEach((votes, index) => {
let value = 100 * votes / total;
let rounded = Math.round(value);
let diff = value - rounded;
if (diff > biggestRound) {
biggestRound = diff;
roundPointer = index;
}
sum += rounded;
result.push(rounded);
});
if (sum === 99) {
result[roundPointer] += 1;
} else if (sum === 101) {
result[roundPointer] -= 1;
}
I want to generate atleast 1000 unique random numbers with 10 digit using
javascript in a loop. Is this possible? Or is Javascript a wrong thing to do this?
UPDATE: How will you be sure that duplicates are not created?
Here's how I would do it:
var arr = [],
track = [],
min = 1000000000,
max = 9999999999,
qty = 1000,
ii = 0,
rnd;
while (ii < qty) {
rnd = Math.floor(Math.random() * (max - min + 1)) + min;
if (!track[rnd]) {
arr[ii] = track[rnd] = rnd;
ii += 1;
}
}
Here's a working example: http://jsfiddle.net/mTmEs/
Now, if something went awry with Math.random and for some reason it were to generate a lot of duplicates, this code could take a long time to complete. I don't think there is any way around this kind of potential problem though when you're talking about large quantities of unique random numbers.
Yes, it's possible.
Use Math.random to generate the pseudo-random numbers. Math.random returns a pseudo-random number greater than or equal to 0 and less than 1, so to get a 10-digit number (I'm assuming a whole number), you'd multiple that by 1,000,000,000 and round it off with Math.round or Math.floor. (If you need them all to be 10 digits, adjust accordingly — adding a base amount, multiplying by a higher number, etc.)
Use an object to keep track of them, so var obj = {}; to start with.
Store the numbers as keys in an object, e.g. obj[number] = true.
Test whether the object has the generated number using if (obj[number])
Loop until you have the correct number of unique numbers.
The reason I use an object for storing the numbers is that JavaScript objects are maps by their nature, and engines are optimized to retrieve properties from objects quickly. Under the covers, an implementation can do what it likes, but will probably use a hash table or similar.
Note that using an "array" for this is unnecessary; JavaScript arrays aren't really arrays, they're just objects with a couple of special features.
You could do this in JS, but you would have to check the array to see if it contains the currently generated random number. This would obviously degrade performance.
See if these answers help.
Random number generator that fills an interval
Generate unique random numbers between 1 and 100
A generic function for generating n random numbers of length l might be:
// Generate n unique random numbers of length l
// l should be less than 15
function genNRandLen(n, l) {
// Make sure l and n are numbers
n = Number(n);
l = Number(l);
// Protect against bad input
if (isNaN(l) || isNaN(n)) return;
var o = {}, a = [], num;
var min = l == 1? 0 : Math.pow(10, l-1);
var r = Math.pow(10, l) - min;
// Protect against endless loop
if (n >= (r)) return;
while (n--) {
do {
num = Math.floor(min + (Math.random()*r));
} while (o[num])
o[num] = true;
a[n] = num;
}
return a.sort();
}
Sorting is just to make it easy to see duplicates when testing, remove if not necessary or random order is preferred.
If numbers longer than 15 digits are required, they can be created by concatenating strings of shorter random numbers and trimming to the required length. The following will generate a random number of any length:
// Generate random number of length l
function randLen(l) {
var n = '';
while (n.length < l) {
n += String(Math.random()).replace(/^0\.0*/,'');
}
return n.substring(0, l);
}
It must return a string since converting to number will mess with the results. Oh, and all numbers are integers.
Why not? Here is the code:
var a=[];
for (var i=1000; i--;)
a.push(Math.random()*10000000000)