I need a random object generator in JavaScript that generates a variety of objects with different fields and values. Any ideas where I can find such tool?
I need to generate random objects with various complexity.. My goal is to use JSON in order to serialize these objects and fuzz test my application http api.
function createRandomObj(fieldCount, allowNested)
{
var generatedObj = {};
for(var i = 0; i < fieldCount; i++) {
var generatedObjField;
switch(randomInt(allowNested ? 6 : 5)) {
case 0:
generatedObjField = randomInt(1000);
break;
case 1:
generatedObjField = Math.random();
break;
case 2:
generatedObjField = Math.random() < 0.5 ? true : false;
break;
case 3:
generatedObjField = randomString(randomInt(4) + 4);
break;
case 4:
generatedObjField = null;
break;
case 5:
generatedObjField = createRandomObj(fieldCount, allowNested);
break;
}
generatedObj[randomString(8)] = generatedObjField;
}
return generatedObj;
}
// helper functions
function randomInt(rightBound)
{
return Math.floor(Math.random() * rightBound);
}
function randomString(size)
{
var alphaChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
var generatedString = '';
for(var i = 0; i < size; i++) {
generatedString += alphaChars[randomInt(alphaChars.length)];
}
return generatedString;
}
It will create a obj with X paramenters, all with a integer, float, string, boolean or null value.
I just made it :B
You can use hasard library
Random variables and random nested objects manipulation in javascript
const h = require('hasard');
const randomInteger = h.integer({type: 'poisson', lambda: 4});
const randomString = h.string({
size: h.add(randomInteger, 5),
value: h.value('abcdefghijklmnopkrstuvw'.split(''))
});
const randomNumber = h.number([0, 100]);
const randomKeys = h.array({
size: randomInteger,
value: randomString
});
// we first define it, to use it as reference into randomObject
const randomValue = h.value();
const randomObject = h.object(
randomKeys,
randomValue
);
// And we set recursivity by setting his values afterward
randomValue.set([
randomString,
randomObject,
randomNumber,
randomInteger
]);
Results will looks like
[
{
"vbmujvv": "rfigcpcvpj",
"sjmcgvvk": 3,
"efdarehl": {
"odinthsuca": "rwjhmbfus",
"noihjtjen": 27.73332043042913,
"brspkaagb": "lnuiabcfd"
},
"febtungjhfokf": 49.28625818957401,
"eoemrkgi": {
"jkcuwrpsh": "ekjoltm",
"cincs": {
"fcovbwk": {
"whsgmjh": 48.00843935524626,
"agsjflef": 46.700796253998014
},
"ovkdfudgfm": 84.83383163217746,
"fpfetl": "djuvfjbjptf",
"kobmkstj": {
"wskgkkerk": 9,
"kvnptptek": 37.63655947554132,
"dsloun": 4
}
},
"krirwk": {
"sjgftomu": 51.663884142674775,
"hpjgibnli": 4
},
"pkhkgruls": "isuodwjrg"
},
"ortomnue": 71.71303423929236
}
]
DISCLAIMER i'm the author of hasard library
Related
This is inspired by a Codecadamey project, where I'm learning JavaScript.
The problem is meant to simulate a simple DNA strand. It has 15 positions in the array, and those elements are either an A, T, C, or G to represent DNA bases.
There are no limits to the amount of times a single letter (base) can show up in the array.
I create 30 arrays that are made up of at least 60% C and/or G in any of the positions, these are meant to represent strong DNA strands.
I compare the strands to each other to see what % match they are. I consider a 'match' being true when there is the same base at the same position thisDNA[i] === comparisonDNA[i]
When I test a batch of 30 of these 'strong' samples to see the best and worst match levels, I find the results very tightly grouped (I ran it 3,000 times and the highest was 87%, lowest 53%), yet it is very easy for me to concieve of two samples that will survive that are a 0% match:
const sample1 = AGACCGCGCGTGGAG
const sample2 = TCTGGCGCGCACCTC
(obviously I've cheated by building these to be a 0% match and not randomly generating them)
Here's the full code: https://gist.github.com/AidaP1/0770307979e00d4e8d3c83decc0f7771
My question is as follows: Why is the grouping of matches so tight? Why do I not see anything below a 53% match after running the test thousands of times?
Full code:
// Returns a random DNA base
const returnRandBase = () => {
const dnaBases = ['A', 'T', 'C', 'G']
return dnaBases[Math.floor(Math.random() * 4)]
}
// Returns a random single stand of DNA containing 15 bases
const mockUpStrand = () => {
const newStrand = []
for (let i = 0; i < 15; i++) {
newStrand.push(returnRandBase())
}
return newStrand
}
const pAequorFactory = (num, arr) => { //factory function for new strand specimen
return {
specimenNum: num,
dna: arr,
mutate() {
//console.log(`old dna: ${this.dna}`) //checking log
let randomBaseIndex = Math.floor(Math.random() * this.dna.length) /// chooses a location to exchange the base
let newBase = returnRandBase()
while (newBase === this.dna[randomBaseIndex]) { // Rolls a new base until newBase !== current base at that position
newBase = returnRandBase()
}
this.dna[randomBaseIndex] = newBase;
//console.log(`New dna: ${this.dna}`) //checking log
return this.dna;
},
compareDNA(pAequor) { // compare two strands and output to the console
let thisDNA = this.dna;
let compDNA = pAequor.dna;
let matchCount = 0
for (i = 0; i < this.dna.length; i++) { //cycles through each array and log position + base matches on matchCount
if (thisDNA[i] === compDNA[i]) {
matchCount += 1;
};
};
let percMatch = Math.round(matchCount / this.dna.length * 100) //multiply by 100 to make 0.25 display as 25 in console log
console.log(`specimen #${this.specimenNum} and specimen #${pAequor.specimenNum} are a ${percMatch}% DNA match.`)
return percMatch;
},
compareDNAbulk(pAequor) { //as above, but does not log to console. Used for large arrays in findMostRelated()
let thisDNA = this.dna;
let compDNA = pAequor.dna;
let matchCount = 0
for (i = 0; i < this.dna.length; i++) {
if (thisDNA[i] === compDNA[i]) {
matchCount += 1;
};
};
let percMatch = Math.round(matchCount / this.dna.length * 100) //multiply by 100 to make 0.25 display as 25 in console log
return percMatch;
},
willLikelySurvive() { // looks for >= 60% of bases as either G or C
let countCG = 0;
this.dna.forEach(base => {
if (base === 'C' || base === 'G') {
countCG += 1;
}
})
//console.log(countCG) // testing
//console.log(this.dna) // testing
return countCG / this.dna.length >= 0.6
},
complementStrand() {
return this.dna.map(base => {
switch (base) {
case 'A':
return 'T';
case 'T':
return 'A';
case 'C':
return 'G';
case 'G':
return 'C';
}
})
} //close method
} // close object
} // close factory function
function generatepAequorArray(num) { // Generatess 'num' pAequor that .willLikelySurvive() = true
let pAequorArray = []; //result array
for (i = 0; pAequorArray.length < num; i++) {
let newpAequor = pAequorFactory(i, mockUpStrand()); // runs factory until there are 30 items in the result array
if (newpAequor.willLikelySurvive() === true) {
pAequorArray.push(newpAequor)
}
}
return pAequorArray;
}
function findMostRelated(array) { // champion/challenger function to find the most related specimens
let winningScore = 0;
let winner1;
let winner2;
for (let i = 0; i < array.length; i++) {
for (let j = i; j < array.length; j++) // j = i to halve the number of loops. i = 0, j = 5 is the same as i = 5, j = 0
if (i !== j) { // Do not check specimen against itself
let currentScore = array[i].compareDNAbulk(array[j]);
if (currentScore > winningScore) { // Challenger becomes the champion if they are a closer match
winningScore = currentScore;
winner1 = array[i].specimenNum;
winner2 = array[j].specimenNum;
}
}
}
let resultArray = [winner1, winner2, winningScore] // stored together for easy return
//console.log(`The most related specimens are specimen #${winner1} and specimen #${winner2}, with a ${winningScore}% match.`)
return resultArray
}
function multiArray(loops) { //test by running finding the closest match in 30 random 'will survive' samples, repaeated 1000 times. Returns the highest and lowest match across the 1000 runs
let highScore = 0;
let lowScore = 100
for (let i = 0; i < loops; i++) {
let pAequorArray = generatepAequorArray(30);
let currentArray = findMostRelated(pAequorArray);
highScore = Math.max(highScore, currentArray[2])
lowScore = Math.min(lowScore, currentArray[2])
}
return results = {
'high score': highScore,
'low score': lowScore
}
}
console.log(multiArray(10000))
So I am looking to create look up tables. However I am running into a problem with integer ranges instead of just 1, 2, 3, etc. Here is what I have:
var ancient = 1;
var legendary = 19;
var epic = 251;
var rare = 1000;
var uncommon = 25000;
var common = 74629;
var poolTotal = ancient + legendary + epic + rare + uncommon + common;
var pool = general.rand(1, poolTotal);
var lootPool = {
1: function () {
return console.log("Ancient");
},
2-19: function () {
}
};
Of course I know 2-19 isn't going to work, but I've tried other things like [2-19] etc etc.
Okay, so more information:
When I call: lootPool[pool](); It will select a integer between 1 and poolTotal Depending on if it is 1 it will log it in the console as ancient. If it hits in the range of 2 through 19 it would be legendary. So on and so forth following my numbers.
EDIT: I am well aware I can easily do this with a switch, but I would like to try it this way.
Rather than making a huge lookup table (which is quite possible, but very inelegant), I'd suggest making a (small) object, choosing a random number, and then finding the first entry in the object whose value is greater than the random number:
// baseLootWeight: weights are proportional to each other
const baseLootWeight = {
ancient: 1,
legendary: 19,
epic: 251,
rare: 1000,
uncommon: 25000,
common: 74629,
};
let totalWeightSoFar = 0;
// lootWeight: weights are proportional to the total weight
const lootWeight = Object.entries(baseLootWeight).map(([rarity, weight]) => {
totalWeightSoFar += weight;
return { rarity, weight: totalWeightSoFar };
});
console.log(lootWeight);
const randomType = () => {
const rand = Math.floor(Math.random() * totalWeightSoFar);
return lootWeight
.find(({ rarity, weight }) => weight >= rand)
.rarity;
};
for (let i = 0; i < 10; i++) console.log(randomType());
Its not a lookup, but this might help you.
let loots = {
"Ancient": 1,
"Epic": 251,
"Legendary": 19
};
//We need loots sorted by value of lootType
function prepareSteps(loots) {
let steps = Object.entries(loots).map((val) => {return {"lootType": val[0], "lootVal": val[1]}});
steps.sort((a, b) => a.lootVal > b.lootVal);
return steps;
}
function getMyLoot(steps, val) {
let myLootRange;
for (var i = 0; i < steps.length; i++) {
if((i === 0 && val < steps[0].lootVal) || val === steps[i].lootVal) {
myLootRange = steps[i];
break;
}
else if( i + 1 < steps.length && val > steps[i].lootVal && val < steps[i + 1].lootVal) {
myLootRange = steps[i + 1];
break;
}
}
myLootRange && myLootRange['lootType'] ? console.log(myLootRange['lootType']) : console.log('Off Upper Limit!');
}
let steps = prepareSteps(loots);
let pool = 0;
getMyLoot(steps, pool);
I want create a array from array by random, but I'm starting on javascript. Here is my question.
//array
var t = ["house","pen","table","eletronic"];
//-> selected a name option 0
var w = t[0]; // selected
var x = w;
var y = 0 to 3; // random
var house =["red","blue","orange","black"];
var pen =["silver", "gold", "cooper","plastic"];
var table =["marble","oak","yep","pine"];
var eletro=["computer","mobile","mac","tablet"];
// what i wish
var z = house[0]; // return red // x = typeof return object
//x this is the error type string not recognize list array query
var z = x[y]; // x = typeof return string
var z = "house"[0]; // return h - return string - not object
//after make a default
var a = x[y]; //y != y
var b = x[y]; //y != y
document.getElementById("demo1").innerHTML=z; // blue house;
document.getElementById("demo2").innerHTML=a; // silver pen;
document.getElementById("demo3").innerHTML=b; // marble table;
<p id "demo1"></p>
<p id "demo2"></p>
<p id "demo3"></p>
I think I must convert double quotes - "house" - string to object - house - to convert to a var and before feed the system?
I'm not 100% sure what you're asking here, but the behaviour i believe you want can be accomplished using 2d arrays as such -
const t = [["red","blue","orange","black"], ["silver", "gold", "cooper","plastic"], ["marble","oak","yep","pine"], ["computer","mobile","mac","tablet"]]
const [rand1, rand2] = [Math.floor(Math.random() * t.length), Math.floor(Math.random() * t[0].length)]
console.log(t[rand1][rand2])
It's not quite clear to me if this is what you're looking for, but one solution might be to structure your data so that it's easier to get at:
const items = {
house: ["red","blue","orange","black"],
pen: ["silver", "gold", "cooper","plastic"],
table: ["marble","oak","yep","pine"],
eletro: ["computer","mobile","mac","tablet"]
}
const randomChoice = list => list[Math.floor(list.length * Math.random())]
const randomObject = (items) => {
const itemType = randomChoice(Object.keys(items))
const modifier = randomChoice(items[itemType])
return `${modifier} ${itemType}`
}
randomObject(items) //=> "marble table" or "plastic pen", etc.
Update
The comment asked to pick a random element of a certain type. This variation would allow for that:
const randomOfType = (items, itemType) => {
const modifier = randomChoice(items[itemType])
return `${modifier} ${itemType}`
}
const randomObject = (items) => randomOfType(items, randomChoice(Object.keys(items)))
randomOfType(items, 'table') //=> "oak table" or "marble table", etc.
You could use the eval() function to obtain the object reference, but it could lead to hairy problems so it would better use another option like for example a switch statement:
//array
var t = ["house","pen","table","electronic"];
var house = ["red","blue","orange","black"];
var pen = ["silver", "gold", "cooper","plastic"];
var table = ["marble","oak","yep","pine"];
var electronic = ["computer","mobile","mac","tablet"];
var w = Math.floor(Math.random() * 3); // random type index (0 to 3)
var x = t[w]; // name of the random type
var y = Math.floor(Math.random() * 3); // random option (0 to 3)
switch (w) { // use the appropriate object based on type index
case 0: z=house[y]; break;
case 1: z=pen[y]; break;
case 2: z=table[y]; break;
case 3: z=electronic[y]; break;
}
console.log(w, z);
var z = z + ' ' + x // appending "house" to color
console.log(z);
document.getElementById("demo1").innerHTML=z;
<p id="demo1"></p>
<p id="demo2"></p>
<p id="demo3"></p>
Imagine that I have a variable called incomingValue and I'm getting a number from an API as it's value. The values are between 0 to 1 and I'm setting two other variables depending on this value using bunch of if statements like you see below.
var incomingValue; // Set by an API
var setValueName;
var setValueIcon;
if (incomingValue < 0.10 ) {
setValueName = 'something';
setValueIcon = 'something.png'
}
if (incomingValue > 0.09 && incomingValue < 0.20 ) {
setValueName = 'somethingElse';
setValueIcon = 'somethingElse.png';
}
In the actual implementation, I have around 10 if statements checking for specific intervals up until 1. e.g. do this if it's more than 0.10 but less than 0.16 and so on.
As a JavaScript beginner it feels like this is not the right way to do things even though it gets the job done. How would I refactor this code?
Update: As requested, I'm adding the full set of intervals that are used in the original code. I haven't included the full list before because the intervals don't follow a certain pattern.
0 to 0.09
0.09 to 0.20
0.20 to 0.38
0.38 to 0.48
0.48 to 0.52
0.52 to 0.62
0.61 to 0.80
0.80 to 1
Remember the single responsibility principle. Take that code out to a separate function like so:
function determineNameAndIcon(incomingValue) {
if (incomingValue < 0.10) {
return {
name: "something",
icon: "something.png"
};
}
if (incomingValue < 0.20) {
return {
name: "somethingElse",
icon: "somethingElse.png"
};
}
// etc
return {
name: "somethingDefault",
icon: "somethingDefault.png"
};
}
// ...
var incomingValue; // Set by an API
const {
name: setValueName,
icon: setValueIcon
} = determineNameAndIcon(incomingValue);
Notice that determineNameAndIcon is still a very long function with repeating parts. This can be further refactored to a data-driven version:
const nameAndIconList = [
{
maxValue: 0.10,
name: "something",
icon: "something.png"
},
{
maxValue: 0.20,
name: "somethingElse",
icon: "somethingElse.png"
},
// ...
];
const nameAndIconDefault = {
name: "somethingDefault",
icon: "somethingDefault.png"
};
function determineNameAndIcon(incomingValue) {
for (let item of nameAndIconList) {
if (incomingValue < item.maxValue) {
return item;
}
}
return nameAndIconDefault;
}
function findValue(incomingValue){
var itemValues = [
[.06, "valueName", "valueIcon"],
[.08, "valueName", "valueIcon"],
[.09, "valueName", "valueIcon"],
[.1, "valueName", "valueIcon"],
]
var foundValues = itemValues.
filter(v=>v[0] >= incomingValue)
.sort();
if(foundValues.length == 0){
throw "incoming value not found."
}
return foundValues[0];
}
let value = findValue(.079);
console.log( value );
This is assuming that you want the lowest portion of the range to be the one selected (just reverse the sort if you want it to be the highest).
A solution using an array where you set the ranges for your results:
var categories = [{something: [0, 0.1]},
{somethingElse: [0.1, 0.2]},
{somethingElse2: [0.2, 0.3]},
{anotherSomething: [0.3, 1]}];
function res(number){ return Object.keys(categories.filter(function(elem) {
var key = elem[Object.keys(elem)];
return number >= key[0] && number < key[1]
})[0])[0]};
var incomingValue = 0.12;
var setValueName = res(incomingValue);
var setValueIcon = res(incomingValue) + ".png";
console.log(setValueName, setValueIcon);
Mb I will refactor this code like this but it's not really standard patter :
var incomingValue=0.08; // Set by an API
var setValueName;
var setValueIcon;
switch(true) {
case incomingValue < 0.10 :
setValueName = "something";
setValueIcon ="something.png";
alert("Hello World !");
break;
case incomingValue > 0.09 && incomingValue < 0.20 :
setValueName = "somethingElse";
setValueIcon ="somethingElse.png";
alert("Hello !");
break;
default :
alert("Adele !");
break;
}
The mortal will use the if...else if... condition like this :
var incomingValue; // Set by an API
var setValueName;
var setValueIcon;
if (incomingValue < 0.10 ) {
setValueName = "something";
setValueIcon ="something.png"
} **else** if (incomingValue > 0.09 && incomingValue < 0.20 ) {
setValueName = "somethingElse";
setValueIcon ="somethingElse.png"
}
But I dont like this way...My opinion :)
In javascript (or jquery) is there a simple function to have four integers with their probability values: 1|0.41, 2|0.29, 3|0.25, 4|0.05
how can I generate these four numbers taking into account their probabilities ?
This question is very similar to the one posted here: generate random integers with probabilities
HOWEVER the solution posted there:
function randomWithProbability() {
var notRandomNumbers = [1, 1, 1, 1, 2, 2, 2, 3, 3, 4];
var idx = Math.floor(Math.random() * notRandomNumbers.length);
return notRandomNumbers[idx];
}
states in the comment "create notRandomNumbers dynamically (given the numbers and their weight/probability)"
This is insufficient for my needs. That works well when the probabilities are say 10%,20%, 60%,10%.
In that case constructing notRandomNumbers with the required distribution is easy and the array size is small. But in the general case where probabilities can be something like 20.354%,30.254% etc , the array size would be huge to correctly model the situation.
Is there a clean solution to this more general problem?
EDIT: Thanks Georg, solution accepted, here is my final version, which may be useful for others. I have split the calculation of the cumulative into a separate function in order to avoid extra additions at each call to get a new random number.
function getRandomBinFromCumulative(cumulative) {
var r = Math.random();
for (var i = 0; i < cumulative.length; i++) {
if (r <= cumulative[i])
return i;
}
}
function getCummulativeDistribution(probs) {
var cumulative = [];
var sum = probs[0];
probs.forEach(function (p) {
cumulative.push(sum);
sum += p;
});
// the next 2 lines are optional
cumulative[cumulative.length - 1] = 1; //force to 1 (if input total was <>1)
cumulative.shift(); //remove the first 0
return cumulative;
}
function testRand() {
var probs = [0.1, 0.3, 0.3, 0.3];
var c = getCummulativeDistribution(probs);
console.log(c);
for (var i = 0; i < 100; i++) {
console.log(getRandomBinFromCumulative(c));
}
}
Just accumulate the probabilities and return an item for which current_sum >= random_number:
probs = [0.41, 0.29, 0.25, 0.05];
function item() {
var r = Math.random(), s = 0;
for(var i = 0; i < probs.length; i++) {
s += probs[i];
if(r <= s)
return i;
}
}
// generate 100000 randoms
a = [];
c = 0;
while(c++ < 100000) {
a.push(item());
}
// test actual distibution
c = {}
a.forEach(function(x) {
c[x] = (c[x] || 0) + 1;
});
probs.forEach(function(_, x) {
document.write(x + "=" + c[x] / a.length + "<br>")
});
Create a second parallel array with corresponding weights and use a "wheel" algorithm to get an index.
function randomWithProbability()
{
var notRandomNumbers = [1,2,3,4];
var w = [0.41, 0.29, 0.25, 0.05];
var placehldr = 0;
var maxProb = 0.41;
var index = Math.floor(Math.random() * w.length);
var i = 0;
placehldr = Math.random() * (maxProb * 2);
while(placehldr > index )
{
placehldr -= w[index];
index = (index + 1) % w.length
}
return (notRandomNumbers[index]);
}
This video has a good explanation as to why it works, it's easier to understand with the visual representation.
https://www.youtube.com/watch?v=wNQVo6uOgYA
There is an elegant solution only requiring a single comparison due to A. J. Walker (Electronics Letters 10, 8 (1974), 127-128; ACM Trans. Math Software 3 (1977), 253-256) and described in Knuth, TAOCP Vol. 2, 120-121.
You can also find a description here, generate random numbers within a range with different probabilities.