Can you replicate tf.random_crop in TensorFlow JS efficiently? - javascript

Random cropping is not implemented in TensorFlow JS, but is it possible to replicate it? My idea was to use Tensor.slice() with tensors generated from tf.randomUniform as parameters, but it only accepts "numbers". So it seems to me, that in order to get random cropping working, I'd have to reconstruct that part of the computation graph in each iteration with newly generated random numbers (e.g. from Math.random()) as slice parameters. Or is there another way?
Here is my code. My understanding is, that the inner function will create the random offset rx and ry only once, and I'd need a tensorflow operation to continuously get random values in each iteration.
export function jitter (d) {
const inner = (tImage) => {
const tShp = tImage.shape;
const cropShape = [
tShp[0], tShp[1]-d,
tShp[2]-d, tShp[3]];
const rx = Math.floor(Math.random() * d + 0.5);
const ry = Math.floor(Math.random() * d + 0.5);
const crop = tImage.slice(
[0, rx, ry, 0],
[cropShape[0], cropShape[1], cropShape[2], cropShape[3]]);
}
return inner;
}
Link to doc for Tensor.slice()

slice will allow to slice or crop a part of the input. Using gatherND will allow on the other hand to slice multiples times if one wants to avoid using slice repeatedly. But the indices at where to slice should be given. Below, the function g generate the indices from the random coordinates and try to calculate the indices of all the z * z elements that will be included in the crop.
const g = (r, s, z, n) => {
const arr = []
for (let i = 0; i < n; i++) {
const c = Math.floor(Math.random() * r)
const d = Math.floor(Math.random() * s)
const p = Array.from({length: z}, (_, k) => k + c)
const q = Array.from({length: z}, (_, k) => k + d)
arr.push(p.map( e => q.map(f => ([e, f]))).flat())
}
return arr
}
const n = 3
const crop = 4
const hsize = 2 // maximum of the height where to start cropping
const wsize = 2 // maximum of the width where to start cropping
// hsize = length_of_height_dimension - crop_size_over_height
// wsize = length_of_width_dimension - crop_size_over_width
const indices = tf.tensor( g(hsize, wsize, crop, n)).toInt()
const input = tf.tensor(Array.from({length: 64 * 3}, (_, k) => k +1), [8, 8, 3]);
tf.gatherND(input, indices).reshape([n, crop, crop, 3]).print()
<html>
<head>
<!-- Load TensorFlow.js -->
<script src="https://cdn.jsdelivr.net/npm/#tensorflow/tfjs#latest"> </script>
</head>
<body>
</body>
</html>

Related

Given min, max, mean and sample size, return a normal distribution as an array using javascript

For example, given:
min = 1
max = 5
Ave = 3
size = 5
ie. at this stage, we have [1,?,?,?,5]
How can I calculate the missing numbers? (This one is easy -> [1,2,3,4,5] - but how do I write a JS function to return this array)
or, given:
min = 23
max = 2500
Ave = 1007
size = 800
ie. at this stage, we have [23,?..,2500]
How can I calculate the missing numbers? (ie. return a completed array (I think this is called uniform distribution...))
Some info about the returned Array
The numbers in the returned array must be rounded to 2 decimal places.
Each number in the array is >= the preceding number.
I expect the distribution if plotted to return a shallow S shaped curve.
This is what I have so far:
const min = 1; //lowest value
const max = 5; //highest value
const ave = 4; //not currently used
const supply = 3; //supply (- 2 because min and max are appended)
const data = Array.from({length: supply}, (_, i) => i + 1);
const distArray = [];
data.map(n => {
distArray.push(Math.round((min+n*(max-min) / (supply+1)) * 1e2 ) / 1e2);
});
distArray.unshift(min);//append min value
distArray.push(max);//append max value
console.log(distArray); // returns [1,2,3,4,5]
The above function returns an array of length supply+2 between the min and max values.
The next step is to include the ave variable. What if you were now told that the average of the 5 numbers was 2.5, not 3 (as it is in the normal distribution from min to max). This would return a different array based on the average value... This is my question - how do I do that?
This is what I have tried, but it's wrong... It kinda works for small arrays, but for larger arrays, the distribution is all concentrated around the middle - I need a better formula to calculate the distribution...
const min = 5; //lowest value
const max = 12; //highest value
const supply = 5; //supply (- 2 because min and max are appended)
const ave = 8; //Average value
const data = Array.from({length: supply}, (_, i) => i + 1);
const distArray = [];
const ksum = (supply + 2) * ave; //known sum
const usum = ksum - (min + max); // unknown sum
const parts = data.reduce((a, n) => a + n, 0);//Num of remainder to share
const b = Math.floor(usum / supply); //base value to add to each
const r = usum % supply; //remainder to share in parts
data.map(n => {
distArray.push(Math.round((b + (n/parts * r)) * 1e2 ) / 1e2);
});
distArray.unshift(min);//append min value
distArray.push(max);//append max value
console.log(distArray); // returns [5, 7.27, 7.53, 7.8, 8.07, 8.33, 12]
Consider the following "math"
avg = sum(all) / size
sum(all) = sum(known) + sum(unknown)
sum(unknown) = avg x size - sum(known)
unknown = sum(unknown) / (size - size(known))
Would that work for you?

Using D3 Scales to convert colour to number

I would like to have this colour scheme as my input domain:
And a value between 0 and 1 as my output range.
However, I am not sure which type of scale to use or how to add the scheme as an input domain.
The code below is the opposite of what I am trying to do.
let scaleSequential1 = d3.scaleSequential()
.domain([0, 1])
.interpolator(d3.interpolateViridis);
console.log( scaleSequential1(0) ); //#440154
console.log( scaleSequential1(0.5) ); //#21918c
console.log( scaleSequential1(1) ); //#fde725
Following up on my comment, there is no direct way to do this. You can hack it up if you like this. If you are going to call it frequently I'd wrap in in a closure to spare the .map...
function invertViridis(color){
return d3.range(0, 1.01, 0.01).map(i => d3.interpolateViridis(i)).indexOf(color) / 100;
}
console.log(invertViridis("#440154"));
console.log(invertViridis("#3b528b"));
console.log(invertViridis("#21918c"));
console.log(invertViridis("#5ec962"));
console.log(invertViridis("#fde725"));
function invertViridisClosure(){
var r = d3.range(0, 1.01, 0.01).map(i => d3.interpolateViridis(i));
return function(color) {
return r.indexOf(color) / 100;
}
}
let f = invertViridisClosure();
console.log(f("#440154"));
console.log(f("#3b528b"));
console.log(f("#21918c"));
console.log(f("#5ec962"));
console.log(f("#fde725"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
I'll suggest a different approach, which deals with D3 source code.
If you look at the d3.interpolateViridis source, you'll see that the colours are just a long string, which is passed to this function:
export default function(specifier) {
var n = specifier.length / 6 | 0, colors = new Array(n), i = 0;
while (i < n) colors[i] = "#" + specifier.slice(i * 6, ++i * 6);
return colors;
}
Then, the above function returns an array of 256 colours.
Therefore, my approach is just using that function (here renamed as getColours) to create our colours array:
const colorsArray = getColors(colorsString);
With that array in hand we can just use indexOf and a basic linear scale, since you explicitly asked for a D3 scale in your question's title. However, we can ditch the scales and use a vanilla JavaScript function:
function invert(color) {
return colorsArray.indexOf(color) / (colorsArray.length - 1);
}
Here is the demo:
const colorsString = "44015444025645045745055946075a46085c460a5d460b5e470d60470e6147106347116447136548146748166848176948186a481a6c481b6d481c6e481d6f481f70482071482173482374482475482576482677482878482979472a7a472c7a472d7b472e7c472f7d46307e46327e46337f463480453581453781453882443983443a83443b84433d84433e85423f854240864241864142874144874045884046883f47883f48893e49893e4a893e4c8a3d4d8a3d4e8a3c4f8a3c508b3b518b3b528b3a538b3a548c39558c39568c38588c38598c375a8c375b8d365c8d365d8d355e8d355f8d34608d34618d33628d33638d32648e32658e31668e31678e31688e30698e306a8e2f6b8e2f6c8e2e6d8e2e6e8e2e6f8e2d708e2d718e2c718e2c728e2c738e2b748e2b758e2a768e2a778e2a788e29798e297a8e297b8e287c8e287d8e277e8e277f8e27808e26818e26828e26828e25838e25848e25858e24868e24878e23888e23898e238a8d228b8d228c8d228d8d218e8d218f8d21908d21918c20928c20928c20938c1f948c1f958b1f968b1f978b1f988b1f998a1f9a8a1e9b8a1e9c891e9d891f9e891f9f881fa0881fa1881fa1871fa28720a38620a48621a58521a68522a78522a88423a98324aa8325ab8225ac8226ad8127ad8128ae8029af7f2ab07f2cb17e2db27d2eb37c2fb47c31b57b32b67a34b67935b77937b87838b9773aba763bbb753dbc743fbc7340bd7242be7144bf7046c06f48c16e4ac16d4cc26c4ec36b50c46a52c56954c56856c66758c7655ac8645cc8635ec96260ca6063cb5f65cb5e67cc5c69cd5b6ccd5a6ece5870cf5773d05675d05477d1537ad1517cd2507fd34e81d34d84d44b86d54989d5488bd6468ed64590d74393d74195d84098d83e9bd93c9dd93ba0da39a2da37a5db36a8db34aadc32addc30b0dd2fb2dd2db5de2bb8de29bade28bddf26c0df25c2df23c5e021c8e020cae11fcde11dd0e11cd2e21bd5e21ad8e219dae319dde318dfe318e2e418e5e419e7e419eae51aece51befe51cf1e51df4e61ef6e620f8e621fbe723fde725";
const colorsArray = getColors(colorsString);
function invert(color) {
return colorsArray.indexOf(color) / (colorsArray.length - 1);
}
console.log(invert("#440154"));
console.log(invert("#21918c"));
console.log(invert("#fde725"));
function getColors(specifier) {
var n = specifier.length / 6 | 0,
colors = new Array(n),
i = 0;
while (i < n) colors[i] = "#" + specifier.slice(i * 6, ++i * 6);
return colors;
}
Have in ind that, because 256 is an even number, there is no colour that will return exactly 0.5. The other answer has a colour returning a nice and beautiful 0.5 because it uses d3.range(0, 1.01, 0.01), which produces an array with an odd number of elements (101 elements).

Is it possible to access d3-shape's algorithm for curveMonotoneX?

I am drawing a line in d3 using curveMonotoneX
import React from 'react';
import { line, curveMonotoneX } from 'd3-shape';
export default function GradientLine(props) {
const { points } = props;
const lineGenerator = line()
.curve(curveMonotoneX)
.x(d => d.x)
.y(d => d.y);
const lineDefinition = lineGenerator(points);
return <path d={lineDefinition} />
For the purposes of creating a tooltip that updates based on the current mouse position, I would like to derive the value of curveMonotoneX at a certain X position. Is this possible? I can supply X in terms of pixels or chart units, and would be happy with an answer in pixels or chart units.
The d3 documentation refers to this paper for the formula to calculate curveMonotoneX for a given set of points. Writing the algorithm myself is an option, but I think it's more of a last resort as it introduces potential bugs from the algorithms not matching up exactly, or d3's algorithm changing in the future.
At this time I do not believe it is possible to access D3's algorithm. I wrote a solver which matches D3's path generator except near the first and last data points. For my needs I was able to mask this issue by adding two extra points to the data set, one before and one after (both offscreen).
export class curveMonotoneSolver {
/* Solver for the monotonic curve interpolation algorithm laid out in
http://adsbit.harvard.edu//full/1990A%26A...239..443S/0000443.000.html
Unfortunately I was not able to get the the curves do not match d3's path
generator around the boundary points, so I opted to implement the first
set of solutions for boundary conditions enumerated in the paper,
"define the unknown slope by the one-sided finite differences" (you can
CTRL-F that sentence). */
constructor(controlPoints) {
this.doPreCalculations(controlPoints);
}
update(controlPoints) {
this.doPreCalculations(controlPoints);
}
doPreCalculations(controlPoints) {
this.controlPoints = controlPoints.map((cp, i) => {
const nextCP = controlPoints[i + 1];
if (nextCP) {
return {
...cp,
h: nextCP.x - cp.x,
s: (nextCP.y - cp.y) / (nextCP.x - cp.x),
};
}
return cp;
});
this.controlPoints = this.controlPoints.map((cp, i) => ({
...cp,
dy: this.getDY(cp, i),
}));
}
getDY(cp, i) {
const lastCP = this.controlPoints[i - 1];
if (i === 0) return cp.s;
if (i === this.controlPoints.length - 1) return lastCP.s;
if (lastCP.s * cp.s <= 0) return 0;
const p = (lastCP.s * cp.h + cp.s * lastCP.h) / (cp.h + lastCP.h);
const comparitor = 2 * Math.min(Math.abs(cp.s), Math.abs(lastCP.s));
if (Math.abs(p) > comparitor) {
return 2 * Math.sign(cp.s) * Math.min(Math.abs(cp.s), Math.abs(lastCP.s));
}
return p;
}
solve(x) {
if (x === null) return null;
const startIndex = this.controlPoints.findIndex(cp => cp.x >= x) - 1;
const startCP = this.controlPoints[startIndex];
const endCP = this.controlPoints[startIndex + 1];
const a = (startCP.dy + endCP.dy - 2 * startCP.s) / Math.pow(startCP.h, 2);
const b = (3 * startCP.s - 2 * startCP.dy - endCP.dy) / startCP.h;
const cubicComponent = a * Math.pow(x - startCP.x, 3);
const squaredComponent = b * Math.pow(x - startCP.x, 2);
const linearComponent = startCP.dy * (x - startCP.x);
return cubicComponent + squaredComponent + linearComponent + startCP.y;
}
}

Constantly increasing memory usage when passing around huge arrays to webworker

I am currently doing some 3d modeling using babylonjs. I need to create a pressure map from given pressure at specific points. I am doing that using IDW. However this means that even with my map being a size of 70x90 grid requires me to have an array of 25200 (4 rgba values for each pixel) entries. Then this buffer is passed to a RawTexture for assigning it to a material, that is overlaid on the object
I am using a web worker, because I have to update the pressure values every 100ms and I don't want to block the main thread.The issue occurs when I am return that array (created in calculate function) from a service worker.
For some reason the memory usage just keeps going up, without stopping. It eventually goes up to around 1.5 gigabytes and I have to kill it.
The question : Is there any way to prevent this and what could be causing such high memory usage?
Worker:
// #flow
import { find, propEq, both } from 'ramda';
import { colorFromValue } from './color';
import { inverseDistance, distanceValues } from './math';
const findPoint = (x: number, y: number) =>
find(both(propEq('x', x), propEq('y', y)));
const distanceDict = {};
/* eslint-disable */
function calculate(options: Object, pList: Array<*>) {
const points = pList || [];
const { height, width } = options;
const gridWidth = width * 4;
const grid = new Uint8Array(options.width * options.height * 4);
for (let y = 0; y < height; y += 1) {
const rW = y * gridWidth;
for (let i = 0; i < gridWidth; i += 4) {
const index = i + rW;
const x = i / 4;
const dictKey = `${x}--${y}`;
let bottoms = distanceDict[dictKey];
if (bottoms === undefined) {
bottoms = distanceValues(points, x, y);
distanceDict[dictKey] = bottoms;
}
const point = findPoint(x, y)(points);
const value = point !== undefined && point !== null ?
point.value : inverseDistance(points, bottoms);
const color = colorFromValue(value);
grid[index] = color[0];
grid[index + 1] = color[1];
grid[index + 2] = color[2];
grid[index + 3] = 255;
}
}
return grid;
}
self.onmessage = (e) => {
const { points, options } = e.data;
const grid = calculate(options, points);
self.postMessage(grid.buffer, [grid.buffer]);
};
Painting:
modifyNodes = (points: Array<*>) => new Promise((res, rej) => {
this.worker.onmessage = (e) => {
this._texture.update(new Uint8Array(e.data));
res();
}
const data = {
options: this._options,
points,
};
this.worker.postMessage(data);
})
So it seems the issue was in the colorFromValue function that was memoized. Because the values had quite few decimal points it could create up to 9! new entries into cache, so it drove up the memory usage...

Create an array with random values

How can I create an array with 40 elements, with random values from 0 to 39 ?
Like
[4, 23, 7, 39, 19, 0, 9, 14, ...]
I tried using solutions from here:
http://freewebdesigntutorials.com/javaScriptTutorials/jsArrayObject/randomizeArrayElements.htm
but the array I get is very little randomized. It generates a lot of blocks of successive numbers...
The shortest approach (ES6):
// randomly generated N = 40 length array 0 <= A[N] <= 39
Array.from({length: 40}, () => Math.floor(Math.random() * 40));
Here's a solution that shuffles a list of unique numbers (no repeats, ever).
for (var a=[],i=0;i<40;++i) a[i]=i;
// http://stackoverflow.com/questions/962802#962890
function shuffle(array) {
var tmp, current, top = array.length;
if(top) while(--top) {
current = Math.floor(Math.random() * (top + 1));
tmp = array[current];
array[current] = array[top];
array[top] = tmp;
}
return array;
}
a = shuffle(a);
If you want to allow repeated values (which is not what the OP wanted) then look elsewhere. :)
ES5:
function randomArray(length, max) {
return Array.apply(null, Array(length)).map(function() {
return Math.round(Math.random() * max);
});
}
ES6:
randomArray = (length, max) => [...new Array(length)]
.map(() => Math.round(Math.random() * max));
Shortest:
[...Array(40)].map(e=>~~(Math.random()*40))
Even shorter ES6 approach:
Array(40).fill().map(() => Math.round(Math.random() * 40))
Also, you could have a function with arguments:
const randomArray = (length, max) =>
Array(length).fill().map(() => Math.round(Math.random() * max))
Math.random() will return a number between 0 and 1(exclusive). So, if you want 0-40, you can multiple it by 40, the highest the result can ever be is what you're multiplying by.
var arr = [];
for (var i=0, t=40; i<t; i++) {
arr.push(Math.round(Math.random() * t))
}
document.write(arr);
http://jsfiddle.net/robert/tUW89/
const randomNumber = Array.from({length: 6}, () => Math.floor(Math.random() * 39));
limited the array to 6 values to make it easy to see.
.. the array I get is very little randomized. It generates a lot of blocks of successive numbers...
Sequences of random items often contain blocks of successive numbers, see the Gambler's Fallacy. For example:
.. we have just tossed four heads in a row .. Since the probability of
a run of five successive heads is only 1⁄32 .. a person subject to the
gambler's fallacy might believe that this next flip was less likely to
be heads than to be tails.
http://en.wikipedia.org/wiki/Gamblers_fallacy
Because * has higher precedence than |, it can be shorter by using |0 to replace Math.floor().
[...Array(40)].map(e=>Math.random()*40|0)
You can generate arrays with 10 random numbers just two lines of code.
let result = new Array(10)
result = result.fill(0).map(() => Math.random());
and just .
console.log(vals);
Since the range of numbers is constrained, I'd say the best thing to do is generate the array, fill it with numbers zero through 39 (in order), then shuffle it.
Using some new ES6 features, this can now be achieved using:
function getRandomInt(min, max) {
"use strict";
if (max < min) {
// Swap min and max
[min, max] = [min, max];
}
// Generate random number n, where min <= n <= max
let range = max - min + 1;
return Math.floor(Math.random() * range) + min;
}
let values = Array.from({length: 40}, () => getRandomInt(0, 40));
console.log(values);
Note that this solution will only work in modern browsers that support these ES6 features: arrow functions and Array.from().
var myArray = [];
var arrayMax = 40;
var limit = arrayMax + 1;
for (var i = 0; i < arrayMax; i++) {
myArray.push(Math.floor(Math.random()*limit));
}
This above is the traditional way of doing it but I second #Pointy and #Phrogz if you want to avoid duplicates in your array without having to do expensive computation
Quirk single-line solutions on every day.
Values in arrays is total random, so when you will be use this snippets, it will different.
An array (length 10) with random chars in lowercase
Array.apply(null, Array(10)).map(function() { return String.fromCharCode(Math.floor(Math.random() * (123 - 97) + 97)); })
[ 'k', 'a', 'x', 'y', 'n', 'w', 'm', 'q', 'b', 'j' ]
An array (length 10) with random integer numbers from 0 to 99
Array.apply(null, Array(10)).map(function() { return Math.floor(Math.random() * 100 % 100); })
[ 86, 77, 83, 27, 79, 96, 67, 75, 52, 21 ]
An array random dates (from 10 years to ago to now)
Array.apply(null, Array(10)).map(function() { return new Date((new Date()).getFullYear() - Math.floor(Math.random() * 10), Math.floor(Math.random() * 12), Math.floor(Math.random() * 29) )})
[ 2008-08-22T21:00:00.000Z, 2007-07-17T21:00:00.000Z,
2015-05-05T21:00:00.000Z, 2011-06-14T21:00:00.000Z,
2009-07-23T21:00:00.000Z, 2009-11-13T22:00:00.000Z,
2010-05-09T21:00:00.000Z, 2008-01-05T22:00:00.000Z,
2016-05-06T21:00:00.000Z, 2014-08-06T21:00:00.000Z ]
An array (length 10) random strings
Array.apply(null, Array(10)).map(function() { return Array.apply(null, Array(Math.floor(Math.random() * 10 + 3))).map(function() { return String.fromCharCode(Math.floor(Math.random() * (123 - 97) + 97)); }).join('') });
[ 'cubjjhaph',
'bmwy',
'alhobd',
'ceud',
'tnyullyn',
'vpkdflarhnf',
'hvg',
'arazuln',
'jzz',
'cyx' ]
Other useful things you may found here https://github.com/setivolkylany/nodejs-utils/blob/master/utils/faker.js
Using Es6
Option 1
new Array(40).fill(0).map(_ => Math.random() * 40 | 0)
creating an empty array of length 40,then filling it with 0 and then replacing zeros with random number.
Math.random() generates floating number,so to float to int,using Bitwise OR(|)
Option 2
[...Array(40)].map(_ => Math.random() * 40 | 0)
replaced new Array(40).fill(0) with [...Array(40)] - it will clone empty(undefined) array of length 40
Option 3
using Array.from
Array.from(arrayLike, mapFn)
arrayLike
An array-like or iterable object to convert to an array.
mapFn (Optional)
Map function to call on every element of the array.
Array.from({length: 10}, () => Math.floor(Math.random() * 100));
If you want to fill with UNIQUE random numbers
We will achieve this using Set,as we know set only allows to add unique values.
let set = new Set();
while (set.size <= 40) {
set.add((Math.random() * 400) | 0);
}
let randomArray = [...set];
But here one thing is important,that you need to multiply with bigger number than array length...otherwise it will take too much time to generate unique number,it might freeze the execution for long time.try to take 10 times bigger number as I take here 400
function shuffle(maxElements) {
//create ordered array : 0,1,2,3..maxElements
for (var temArr = [], i = 0; i < maxElements; i++) {
temArr[i] = i;
}
for (var finalArr = [maxElements], i = 0; i < maxElements; i++) {
//remove rundom element form the temArr and push it into finalArrr
finalArr[i] = temArr.splice(Math.floor(Math.random() * (maxElements - i)), 1)[0];
}
return finalArr
}
I guess this method will solve the issue with the probabilities, only limited by random numbers generator.
I am pretty sure that this is the shortest way to create your random array without any repeats
var random_array = new Array(40).fill().map((a, i) => a = i).sort(() => Math.random() - 0.5);
Refer below :-
let arr = Array.apply(null, {length: 1000}).map(Function.call, Math.random)
/* will create array with 1000 elements */
from the page suggested by #Phrogz
for (var i=0,nums=[];i<49;i++) nums[i]={ n:i, rand:Math.random() };
nums.sort( function(a,b){ a=a.rand; b=b.rand; return a<b?-1:a>b?1:0 } );
I needed something a bit different than what these solutions gave, in that I needed to create an array with a number of distinct random numbers held to a specified range. Below is my solution.
function getDistinctRandomIntForArray(array, range){
var n = Math.floor((Math.random() * range));
if(array.indexOf(n) == -1){
return n;
} else {
return getDistinctRandomIntForArray(array, range);
}
}
function generateArrayOfRandomInts(count, range) {
var array = [];
for (i=0; i<count; ++i){
array[i] = getDistinctRandomIntForArray(array, range);
};
return array;
}
I would have preferred to not create a loop that has the possibility to end up with a lot of unnecessary calls (if your count, and range are high and are close to the same number) but this is the best I could come up with.
If you need it with random unique values from 0...length range:
const randomRange = length => {
const results = []
const possibleValues = Array.from({ length }, (value, i) => i)
for (let i = 0; i < length; i += 1) {
const possibleValuesRange = length - (length - possibleValues.length)
const randomNumber = Math.floor(Math.random() * possibleValuesRange)
const normalizedRandomNumber = randomNumber !== possibleValuesRange ? randomNumber : possibleValuesRange
const [nextNumber] = possibleValues.splice(normalizedRandomNumber, 1)
results.push(nextNumber)
}
return results
}
randomRange(5) // [3, 0, 1, 4, 2]
A little late to the party, but I use randojs.com for randomness because it makes stuff like this super easy. You can get a randomly shuffled array of numbers from 0 through 39 just like this:
console.log(randoSequence(40));
<script src="https://randojs.com/1.0.0.js"></script>
No fuss with the logistics of it all- plus it's super readable and easy to understand :)
Generators
An array of length 40 of 40 random possible values (0 - 39) without repeating values is better to shuffle it as #Phrogz and #Jared Beck explain.
Another approach, just for the records, could be using generators. But this approach lacks of performance compared to other proposed solutions.
function* generateRandomIterable(n, range) {
for (let i = 0; i < n; i++) {
yield ~~(Math.random() * range);
}
}
const randomArr = [...generateRandomIterable(40,40)];
Here is a ES6 function that allows a min and a max and will generate an array of unique values in random order that contain all the number from min to max inclusive:
const createRandomNumbers = (min, max) => {
const randomNumbers = new Set()
const range = max - min + 1
while (randomNumbers.size < range) {
randomNumbers.add(~~(Math.random() * range))
}
return [...randomNumbers]
}

Categories

Resources