Picking a few random properties from an Object - javascript

If I have a few objects as below:
var points = {'p1':{x:1,y:1,z:2}, 'p2':{x:2,y:1,z:4},.....,'p10':{x:3,y:2:z:2}};
var lines = {'l1':{....},'l2':{....},......,'l10'{....}};
var jsonObject = {'info': 'information', 'points': points, 'lines': lines};
How do I pick (for example, 3 random points and 3 random lines) from respective objects and update in jsonObject such that the new jsonObject now contains {'info': 'information', 'points': pointObj, 'lines': lineObj}; where pointObj contains 3 random points from the orighinal points object and lineObj contains 3 random lines from the original lines object?

As its an Object with keys, you can use Object.keys to get its all keys as an array:
var getRandoms = function(source, number) {
var keys = Object.keys(source) // get all keys as array
,len = keys.length; // keys count
var result = {};
// not enough points, so just return all object from source.
if (len < number) {
return source;
}
var rand, key, count = 0;
while (count < number) {
rand = Math.floor(Math.random() * len);
key = keys[rand];
result[key] = source[key];
// Remove used key
keys.splice(rand, 1);
--len;
++count;
}
return result;
}
jsonObject.points = getRandoms(points, 3);
jsonObject.lines = getRandoms(lines, 3);

Create a function which return randomly chosen number between [0-10)
function get3RandomPoint(){
var temp, arr=[];
while(arr.length < 3) {
temp = Math.ceil(Math.random()*10);
if(arr.indexOf(temp) === -1) {
arr.push(temp);
}
}
return arr;
}
var points = {'p1':{x:1,y:1,z:2}, 'p2':{x:2,y:1,z:4},.....,'p10':{x:3,y:2:z:2}};
var lines = {'l1':{....},'l2':{....},......,'l10'{....}};
var randomNums = get3RandomPoint();
var randomPoints = {p1: points["p"+ randomNums[0]], p2: points["p"+ randomNums[1]], p2: points["p"+ randomNums[2]]};
randomNums = get3RandomPoint();
var randomLiness = {l1: points["l"+ randomNums[0]], l2: points["l"+ randomNums[1]], l2: points["l"+ randomNums[2]]};
var jsonObject = {'info': 'information', 'points': randomPoints, 'lines': randomLiness};
console.log(jsonObject);

Use a random() function.
var randomNum = Math.floor((Math.random() * 10));
Now based on the randomNum pick an entry using it's index.
var jsonObject = {
"points" : [],
"lines" : []
};
var count = 0;
while(count <3)
{
var randomNum = Math.floor((Math.random() * 10))
jsonObject["points"].push(points[randomNum][0]);
randomNum = Math.floor((Math.random() * 10));
jsonObject["lines"].push(lines[randomNum][0]);
count++;
}

Related

Javascript to get the Random sample of data

Hi all,
I am working on a dataset on Google Sheet and I need to get the random data (specified number) by the col 3 names to audit I am using google app script for the same but couldn't able to get the data. Here's the code I tried but I don't want the % of data I want the equally distributed random data for each employee in col 3.
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var trn = ss.getSheetByName('Data');
var originalData = trn.getRange(2, 1, trn.getLastRow() - 1, 3).getValues();
var ReviewerEmail = data;
var data = originalData.filter(function(item) {
return item[1] === 'rob' || item[1] === 'john' || item[1] === 'toger';
});
//Logger.log(data);
var targetsheet = ss.insertSheet(Reviewer);
targetsheet.getRange(1, 1, data.length, data[0].length).setValues(data);
}
function getsampledata() {
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getRange('A:C');
var values = range.getValues();
var headers = values.shift();
var nameColumn = 1;
var uniqueNames = values
.map((row) => row[nameColumn])
.filter((item, i, ar) => ar.indexOf(item) === i)
.filter(String);
var data = [headers];
uniqueNames.forEach(function(name) {
var nameEntries = values.filter((row) => row[nameColumn] == name);
var entries = nameEntries.length;
var tenth = Math.round((entries / 100) * 27.35); //Sampling Percentage
for (i = 0; i < tenth; i++) {
var random = Math.floor(Math.random() * nameEntries.length);
data.push(nameEntries[random]);
nameEntries.splice(random, 1);
}
});
return data;
}
If you want a specific number of sample, then use a parameter to indicate how many you want for each.
Whole working script:
function getsampledata(sample) {
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getRange('A:C');
var values = range.getValues();
var headers = values.shift();
var nameColumn = 2;
var uniqueNames = values
.map((row) => row[nameColumn])
.filter((item, i, ar) => ar.indexOf(item) === i)
.filter(String);
var data = [headers];
uniqueNames.forEach(function(name) {
var nameEntries = values.filter((row) => row[nameColumn] == name);
for (i = 0; i < sample; i++) {
var random = Math.floor(Math.random() * nameEntries.length);
data.push(nameEntries[random]);
nameEntries.splice(random, 1);
}
});
return data;
}

How do I avoid specific 3 element combinations using rand and split function?

I have a variable with 7 elements and I need to select 3 elements at random, but here are specific 3 element combinations i want it to avoid. How do I code this?
(ex. I need it to avoid the combination [2,5,7] and [1,3,6])
This is what i have so far:
var Allregions = [
'1',
'2',
'3',
'4',
'5',
'6',
'7']
var ShowRegions = [];
do {
ShowRegions [ShowRegions.length] = Allregions.splice(
Math.floor(Math.random() * Allregions.length)
, 1)[0];
} while (ShowRegions.length < 3);
EDIT: I wanted to clarify something: The "numbers" are just placeholders, as they are actually calling elements from different parts of the code. i.e. 1 is actually something like "page banner". So the code I had written was fine in selecting 3 unique elements to populate a webpage, but it didn't allow me to control which 3 element combination is (not)shown.
This function will return a random number without sequence of repeated letters & without excludes.
var allRegions = ['1', '2', '3', '4', '5', '6', '7'];
// to skip sequence of repeated letters.
var isSequence = /^([a-zA-Z0-9])\1+$/;
// to skip, if the combination has duplicates.
var hasDuplicates = /([a-zA-Z0-9]).*?\1/;
function isNotUniqueCombination(ex, rand) {
for (var n = 0; n < ex.length; n++) {
var e = ex[n];
var combinations = [
[e[0], e[1], e[2]],
[e[0], e[2], e[1]],
[e[1], e[0], e[2]],
[e[1], e[2], e[0]],
[e[2], e[0], e[1]],
[e[2], e[1], e[0]]
];
for (var i = 0; i < combinations.length; i++) {
var com = combinations[i];
if (com.join("") === rand.join("")) return true;
}
}
return false;
}
/**
* Return a random number without sequence of repeated letters & without excludes
* #param {String} array
* #param {String} excludes
*/
function getRandom(array, excludes) {
// Random number array
var randomNumber = [];
var excludesMap = excludes.map(function(e) {
return e.join("");
});
do {
// Generate random number
randomNumber = [
array[Math.floor(Math.random() * array.length)],
array[Math.floor(Math.random() * array.length)],
array[Math.floor(Math.random() * array.length)]
];
} while (excludesMap.indexOf(randomNumber.join("")) !== -1 || isSequence.test(randomNumber.join("")) || hasDuplicates.test(randomNumber.join("")) || isNotUniqueCombination(excludes, randomNumber));
return randomNumber;
}
var excludes = [
['2', '5', '7'],
['1', '3', '6']
];
// Test Case
// =========
for (var i = 0; i < 1e3; i++) {
var arr = getRandom(allRegions, excludes);
var div = document.createElement('div');
div.innerHTML = arr.join("");
document.body.appendChild(div);
// Check if the string contains a sequence of repeated letters of has duplicates
if (isSequence.test(arr.join("")) || hasDuplicates.test(arr.join("")) || isNotUniqueCombination(excludes, arr)) {
div.style.color = "#ff0000";
div.innerHTML += " [ sequence of repeated letters found || duplicates found ]";
document.body.appendChild(div);
break;
}
}
// ===
You can pass the excluded sets to a function, if the result of random selection matches an excluded set call the function again
var Allregions = ["1","2","3","4","5","6","7"];
function randomNot(arr, not) {
var curr = arr.slice();
var ShowRegions = [];
do {
ShowRegions[ShowRegions.length] = curr.splice(
Math.floor(Math.random() * curr.length), 1)[0];
} while (ShowRegions.length < 3);
return not.some(function(n) {
return n === ShowRegions.join("")
}) ? randomNot(arr, not) : ShowRegions
}
var not = ["257", "136"];
var res = randomNot(Allregions, not);
console.log(res);
Use IndexOf() Method to exclude the paticular number from the array list. Here is the modified code.
var Allregions = ['1','2','3','4','5','6','7'];
var ShowRegions = [];
randomNot(); // call the function to generate the number
function randomNot(){
do {
ShowRegions [ShowRegions.length] = Allregions.splice(Math.floor(Math.random() * Allregions.length), 1)[0];
}
while (ShowRegions.length < 3);
}
console.log("Response: "+ShowRegions);
var excludeNo = new Array("2,5,7", "1,3,6");
if(excludeNo.indexOf(ShowRegions) != -1){
console.log("Excluded Number");
randomNot();
}
document.getElementById("exclude").innerHTML = ShowRegions;
<p id="exclude"></p>

Calculate percentage from associative array in JS

Suppose I have an array like this:
var arr = [];
arr["india"] = 7;
arr["indonesia"] = 3;
arr["usa"] = 1;
[india: 7, indonesia: 3, usa: 1]
I need to get an array like [india: (7/11*100), indonesia: (3/11*100), usa: (1/11*100)] , i.e., to get the percentage of each country value using a single loop in javascript. How can I achieve it ?
You can use array#reduce to sum up all values and then calculate percentages inside array#map
var arr = {};
arr["india"] = 7;
arr["indonesia"] = 3;
arr["usa"] = 1;
let sum = Object.keys(arr).reduce((s,k) => s += arr[k], 0);
var result = Object.keys(arr).map(k => ({[k] : (arr[k]/sum * 100).toFixed(2)}));
console.log(result);
If your objects is like this var arr = {india: 7, indonesia: 3, usa: 1};, you can do it in this way.
var arr = {india: 7, indonesia: 3, usa: 1};
var sum = 0;
//Finding the sum
for(key in arr){
sum += arr[key];
}
console.log("Sum of the object values is = " + sum);
//Finding the average
for(key in arr){
arr[key] = (arr[key]/sum)*100;
}
console.log(arr);
Loop through each key and reassigned the val like this:
var countries = [];
countries["india"] = 7;
countries["indonesia"] = 3;
countries["usa"] = 1;
for (var country in countries){
if (countries.hasOwnProperty(country)) {
countries[country] = (countries[country] / 11 * 100).toFixed(2)
}
}
console.log(countries)
[india: 7, indonesia: 3, usa: 1]is wrong, you need an object, like {india: 7, indonesia: 3, usa: 1}
So, I think you need an function to do what you need, simple:
var obj = {india: 7, indonesia: 3, usa: 1}
const getPercent = (obj) {
let sum = 0
for (key in obj) {
sum += obj[key]
}
for (key in obj) {
obj[key] = (obj[key]/sum)*100
}
return obj
}
Once you change the obj, you run getPercent(obj), then you get a return, that is what's you need.
May helpful.
So, suppose you have a valid array:
var myArray = { 'key1': 2, 'key2': 5, 'key3': 14 };
/* iterates through an associative array, calculates each percentage and
adds it to a similar associative array
The percentages are not rounded
*/
function getPercentagePerKey(myArray) {
var sum = getSum(myArray);
var arrayWithPercentages = [];
for (key in myArray) {
val = myArray[key];
percentage = (val / sum) * 100;
arrayWithPercentages.push({key, percentage});
}
return arrayWithPercentages;
}
/* returns the sum given from an 'associative' array */
function getSum(myArray) {
var sum = 0;
for (key in myArray) {
sum += myArray[key];
}
return sum;
}
percentageArray = getPercentagePerKey(myArray);
console.log(percentageArray);
0: {key: "key1", percentage: 9.523809523809524}
1: {key: "key2", percentage: 23.809523809523807}
2: {key: "key3", percentage: 66.66666666666666}
You can make getters from object properties if it is allowed:
var arr = {};
arr["india"] = 7;
arr["indonesia"] = 3;
arr["usa"] = 1;
var sum = 0;
var percent = function(n){
return function(){ return n/sum*100; }
}
for (var k in arr) {
sum+=arr[k];
arr[k]=percent(arr[k]);
}
console.log(arr.india());
console.log(arr.usa());
console.log(arr.indonesia());

Push different object in an array with a for loop

I have an element structured like this:
Element ->
[{values: arrayOfObject, key:'name1'}, ... ,{values: arrayOfObjectN, key:'nameN'}]
arrayDiObject -> [Object1, Object2, ... , ObjectN] //N = number of lines in my CSV
Object1 -> {x,y}
I have to take data from a big string:
cityX#substanceX#cityY#substanceY#
I thought to make it this way, but it seems like it pushes always in the same array of objects. If I put oggetto = {values: arrayDateValue, key: key}; inside the d3.csv function, instead if I put outside the function it add me only empty objects.
Here is my code:
var final = new Array();
var oggetto;
var key;
function creaDati() {
var newdate;
var arrayDateValue = new Array();
var selString = aggiungiElemento().split("#");
//selString is an array with selString[0]: city, selString[1]: substance and so on..
var citySelected = "";
var substanceSelected = "";
for (var i = 0; i < selString.length - 1; i++) {
if (i % 2 === 0) {
citySelected = selString[i];
} else if (i % 2 !== 0) {
substanceSelected = selString[i];
key = citySelected + "#" + substanceSelected;
d3.csv("/CSV/" + citySelected + ".csv", function(error, dataset) {
dataset.forEach(function(d) {
arrayDateValue.push({
x: d.newdate,
y: d[substanceSelected]
});
});
});
oggetto = {
values: arrayDateValue,
key: key
};
arrayDateValue = [];
final.push(oggetto);
}
}
}
Any idea ?
First you should make the if statement for the city and then for the key, which you seem to be doing wrong since you want the pair indexes to be the keys and the not pair to be the city, and you are doing the opposite. And then you need to have the d3.csv and push the objects outside of the if statement, otherwise in your case you are just adding elements with citySelected="".
Try something like :
for(var i = 0; i < selString.length -1; i+=2){
cittySelected = selString[i];
substanceSelected = selString[i+1];
key = citySelected + "#" + substanceSelected;
d3.csv("/CSV/"+citySelected+".csv", function(error, dataset){
dataset.forEach(function(d){
arrayDateValue.push({x: d.newdate, y: d[substanceSelected]});
});
});
oggetto = {values: arrayDateValue, key: key};
arrayDateValue = [];
final.push(oggetto);
}
It's is not the best way to do it, but it is clearer that what you are following, i think.
In the if(i % 2 == 0) { citySelected = ... } and else if(i % 2 !== 0) { substanceSelected = ... } citySelected and substanceSelected will never come together.
The values should be in one statement:
if(...) { citySelected = ...; substanceSelected = ...; }
The string can be splitted into pairs
city1#substance1, city2#substance2, ...
with a regex (\w{1,}#\w{1,}#).
Empty the arrayDateValue after the if-statement.
Hint:
var str = "cityX#substanceX#cityY#substanceY#";
function createArr(str) {
var obj = {};
var result = [];
var key = "";
// '', cityX#substanceX, '', cityYsubstanceY
var pairs = str.split(/(\w{1,}#\w{1,}#)/g);
for (var i = 0; i < pairs.length; i++) {
if(i % 2 !== 0) {
key = pairs[i];
// d3 stuff to create values
obj = {
// Values created with d3 placeholder
values: [{x: "x", y: "y"}],
// Pair
key: key
};
result.push(obj);
}
// Here should be values = [];
}
return result;
}
var r = createArr(str);
console.log(r);
May be you can do like this;
var str = "cityX#substanceX#cityY#substanceY",
arr = str.split("#").reduce((p,c,i,a) => i%2 === 0 ? p.concat({city:c, key:a[i+1]}) : p,[]);
console.log(JSON.stringify(arr));
RESOLVED-
The problem is about d3.csv which is a asynchronous function, it add in the array when it finish to run all the other code.
I make an XMLHttpRequest for each csv file and it works.
Hope it helps.

Display number if each item in JavaScript array

I am trying to display the contents of an array in a more readable way, this is the array:
["malevolent", "pariah", "judicious", "pariah", "judicious"]
I'm simply adding that array to an HTML element to display it, but I want to display it like this:
malevolent, pariah x 2, judicious x2
How would I do this?
It's quite simple actually:
var myArray = new Array("a", "b", "c", "b", "a");
var newObject = {};
// Iterate over the array
for(var i = 0; i < myArray.length; i++){
// If the new object already contains the key (e.g. a, b, or c), increment value by one
if(myArray[i] in newObject){
newObject[myArray[i]]++;
} else {
// Otherwise add a key (e.g. a, b, or c) to the object and assign 1 to it (first occurence)
newObject[myArray[i]] = 1;
}
}
// Write the resulting object to console
window.console && console.log(newObject);
newObject contains a list of keys (a,b,c) and values (number of occurrences of each key). You can than use that data to output it in any format you like, but that's left up to you as an excercise.
You can try the following:
var myArray = ["malevolent", "pariah", "judicious", "pariah", "judicious"];
var resultArray = [];
var countArray = [];
for(index in myArray) {
var element = myArray[index];
var isInArray = resultArray.indexOf(element);
if(isInArray !== -1) {
var tmpCnt = countArray[isInArray];
tmpCnt++;
countArray[isInArray] = tmpCnt;
} else {
resultArray.push(element);
countArray.push(1);
}
}
console.log(resultArray);
console.log(countArray);
Felix Kling provided a Link to an answer on how to count your elements. I just shamelessly use the reduce method described there and then just iterate over the object to build a string.
var a = ["malevolent", "pariah", "judicious", "pariah", "judicious"].reduce(function (acc, curr) {
if (typeof acc[curr] == 'undefined') {
acc[curr] = 1;
} else {
acc[curr] += 1;
}
return acc;
}, {});
var out = "";
for (var k in a) {
out += k + " x " + a[k] + "; ";
}
console.log(out);
try this
var arr = new Array("malevolent", "pariah", "judicious", "pariah", "judicious");
var new_arr1 = new Array(); // for containing distinct values like pariah
var new_arr2 = new Array(); // for containing distinct values count like 2 for pariah
// both will be on same index in new_arr1 and new_arr2
for(var i=0; i<arr.length; i++)
{
// fetch every value of arr
var indx = $.inArray(arr[i], new_arr1); // check value is exists in new_arr1 and get index
if(indx > -1) // values exists in new_arr1
{
var v = new_arr2[indx]+1; // increment the previous count +1
new_arr2[indx] = v; // update it on the index of new_arr2
}
else
{
// if value not in new_arr1 means the value comes first time
var l = new_arr1.length;
new_arr1[l] = arr[i]; // insert value in new_arr1
new_arr2[l] = 1; // initate count 1 for the same index of new value in new_arr2
}
}
// now new_arr1 will contains the distinct values
// and new_arr2 contains the count for distinct values
// eg new_arr1[0] = 'malevolent';
// new_arr2[0] = 1;
// new_arr1[1] = 'pariah';
// new_arr2[1] = 2;
// now you can fetch distinct values and their count like given below
for(var i=0; i<new_arr1.length; i++)
{
var str = new_arr1[i]+" X "+new_arr2[i];
alert(str);
}
See FIDDLE

Categories

Resources