Manipulating JSON with LoDash - javascript

I've just started working with Lodash, and am trying to average out any value (at the lowest level) that's an array. No matter what I try, the original JSON persists.
Do I need to build a brand new object and push everything into it? Why can't I simply manipulate it like I would an array?
function averageIt(mtcs) {
function jsonAvg(dataSet) {
function avg(elmt) {
var sum = 0;
for( var i = 0; elmt[i]; i++ ){
sum += parseInt( elmt[i], 10 );
}
return Math.round(sum/elmt.length * 100) / 100;
}
_.forEach(dataSet.json, function(day) {
_.mapValues(day, function(n) {
return _.isArray(n) ? avg(n) : n;
});
});
console.log("JSON Averaged:", dataSet.json);
return dataSet;
}
_.forIn(mtcs.dataSets, function(set) {
set = jsonAvg(set);
});
console.log("Averaged Metrics:", mtcs);
return mtcs;
}
Regards
- - - Really Confused "Programmer"

If I understand it correctly, when you use _.mapValues is where the avg function is applied. But as you are using a map function, the result you set in the return is not stored anywhere, and the dataSet.json remains the same. You could do this:
_.each(dataSet.json, function(day, index) {
dataSet.json[index] = _.mapValues(day, function(n) {
return _.isArray(n) ? avg(n) : n;
});
});
Supposing that dataSet.json is an array. If it is an object, you should not apply an each to it, but do something like Object.keys(dataSet.json) to convert its properties to an array.

Related

how to sort object with key value date as key

I have the following object which I would like to sort. the key is date field in Unix and I will need to keep the value for each key. the examples that I have seen get rid of the value but sort the key.
{
"1458345600000":598.15,
"1458432000000":498.77000000000004,
"1458604800000":598.4699999999999,
"1458691200000":598.2900000000001,
"1458777600000":598.26,
"1458864000000":697.79,
"1459206000000":598.21,
"1459292400000":598.2800000000001,
"1459638000000":598.74,
"1457481600000":566.88,
"1457568000000":466.02000000000004,
"1457654400000":470.36,
"1457740800000":481.25,
"1457827200000":484.74000000000007,
"1457913600000":575.8199999999999,
"1458000000000":498.83000000000004,
"1458086400000":498.76,
"1458172800000":598.73,
"1458259200000":598.93,
"1458518400000":499.03999999999996,
"1458950400000":498.14,
"1459036800000":498.78,
"1459119600000":498.65999999999997,
"1459378800000":598.66,
"1459465200000":598.95,
"1459551600000":497.05
}
The key is an integer value;
UPDATE
I have tried the following which still does not work
var map = arr_cssr[key];
console.log(JSON.stringify(map));
Object.keys(map).sort((a,b) => parseInt(a) > parseInt(b));
console.log(JSON.stringify(map));
var subarr = [];
for ( var k in map) {
console.log(moment.unix(parseInt(k)/1000).format('YYYY-MM-DD'));
subarr.push({
0 : parseInt(k),
1 : map[k]/count
});
}
result
{"1458345600000":595,"1458432000000":496,"1458604800000":595,"1458691200000":595,"1458777600000":595,"1458864000000":695,"1459206000000":596,"1459292400000":595,"1459638000000":597,"1459724400000":595,"1459810800000":695,"1457481600000":566,"1457568000000":463,"1457654400000":468,"1457740800000":480,"1457827200000":483,"1457913600000":574,"1458000000000":496,"1458086400000":496,"1458172800000":596,"1458259200000":596,"1458518400000":495,"1458950400000":495,"1459036800000":496,"1459119600000":496,"1459378800000":595,"1459465200000":596,"1459551600000":494}
{"1458345600000":595,"1458432000000":496,"1458604800000":595,"1458691200000":595,"1458777600000":595,"1458864000000":695,"1459206000000":596,"1459292400000":595,"1459638000000":597,"1459724400000":595,"1459810800000":695,"1457481600000":566,"1457568000000":463,"1457654400000":468,"1457740800000":480,"1457827200000":483,"1457913600000":574,"1458000000000":496,"1458086400000":496,"1458172800000":596,"1458259200000":596,"1458518400000":495,"1458950400000":495,"1459036800000":496,"1459119600000":496,"1459378800000":595,"1459465200000":596,"1459551600000":494}
2016-03-19
2016-03-20
2016-03-22
2016-03-23
2016-03-24
2016-03-25
2016-03-29
2016-03-30
2016-04-03
2016-04-04
2016-04-05
2016-03-09
2016-03-10
2016-03-11
2016-03-12
2016-03-13
2016-03-14
2016-03-15
2016-03-16
2016-03-17
2016-03-18
2016-03-21
2016-03-26
2016-03-27
2016-03-28
2016-03-31
2016-04-01
2016-04-02
You can't sort an object. It's unordered. You can use Map instead, or just sort its keys.
Object.keys(obj).sort((a,b) => a > b);
I think it doesn't makes any sense to sort a Javascript object having key value pairs. Though in array it does actually makes sense as you will be changing the index of the elements but in this object we don't want that.
Still if you want all the values sorted by keys you can use something like this:
var data = {
"1458345600000": 598.15,
"1458432000000": 498.77000000000004,
"1458604800000": 598.4699999999999,
"1458691200000": 598.2900000000001,
"1458777600000": 598.26,
"1458864000000": 697.79,
"1459206000000": 598.21,
"1459292400000": 598.2800000000001,
"1459638000000": 598.74,
"1457481600000": 566.88,
"1457568000000": 466.02000000000004,
"1457654400000": 470.36,
"1457740800000": 481.25,
"1457827200000": 484.74000000000007,
"1457913600000": 575.8199999999999,
"1458000000000": 498.83000000000004,
"1458086400000": 498.76,
"1458172800000": 598.73,
"1458259200000": 598.93,
"1458518400000": 499.03999999999996,
"1458950400000": 498.14,
"1459036800000": 498.78,
"1459119600000": 498.65999999999997,
"1459378800000": 598.66,
"1459465200000": 598.95,
"1459551600000": 497.05
};
var valuesSorted = Object.keys(data).sort().map(function(el) {
return data[el];
});
console.log(valuesSorted);
now valuesSorted will be array having all the values sorted by their respective keys. Though please consider changing the sort compare function according to your need.
var a = { ... };
var sorted = Object.keys(a).map(k=>parseInt(k)).sort((a,b)=>a-b).map(k=>a[k.toString()]);
Numeric sort with explicit type conversion.
var map = { };
map = Object.keys(map);
map.sort(function(x, y) {
if (x > y) return -1;
if (x < y) return 1;
if (x == y) return 0;
});
I had to sort the keys then get the value from original object
var map = arr_cssr[key];
map = Object.keys(map);
map.sort(function(x, y) {
if (x > y) return -1;
if (x < y) return 1;
if (x == y) return 0;
});
var subarr = [];
for (var i = 0; i < map.length; i++) {
subarr.push({
0 : parseInt(map[i]),
1 : arr_cssr[key][map[i]]/count
});
}

How to add up numbers in a nested array javascript

Just working on a project and tried a few different solutions but with no results. Could someone help me with how to add up numbers in a nested array? Would I use reduce? or a for loop?
function balance(arr) {
if(typeof item == 'number') {
return arr;enter code here
} else {
return arr + balance(item);
}
}
Is this maybe what you are hoping for?
function balance(arr) {
return arr.reduce(function(sum, item) {
if(typeof item == 'number') {
return sum;
} else {
return sum + balance(item);
}
},0);
}
console.log(balance([1,2,[3,4],5]));
Just for the record (to disprove the assertion that recursion is required), here's a version that uses a sequential algorithm. Recursion is concise and (usually) easier to read, however if speed matters, it can be slow. However, based on results from jsPerf, script engines seem very much better at optimising recursive code than they used to be, at least for simple programs like this.
For comparison, I've included a recursive version using a plain loop, the jsPerf tests also include a (fixed) recursive version using reduce. I suspect Any's answer will be slowest as it calls slice and itself on every loop, but I didn't have time to fix it.
So I guess recursion is fine here as it is fast and concise.
/* Sum the values of nested arrays. Only checks if values are arrays,
** otherwise assumes they're numbers
**
** #param {Array} arr - array of numbers to process, may have
** nested arrays of numbers
** #returns {number} - sum of values or NaN if arr is not an Array
*/
function balance(arr) {
// Only process arrays
var isArray = Array.isArray;
if (!isArray(arr)) return NaN;
// Setup
var arrays = [], indexes = [];
var currentArray = arr;
var currentValue;
var sum = 0;
var i = 0, iLen = arr.length;
// Use <= length as must handle end of array inside loop
while (i <= iLen || arrays.length) {
currentValue = currentArray[i];
// If at end of current array, reset value to before entering array
// Reset i to previous value as will increment at the bottom
if (i == currentArray.length && arrays.length) {
currentArray = arrays.pop();
i = indexes.pop();
iLen = currentArray.length;
// If current value is an array, use it and reset loop control values
// set i to -1 as will increment at the bottom
} else if (isArray(currentValue)) {
arrays.push(currentArray);
indexes.push(i);
currentArray = currentValue;
i = -1;
iLen = currentArray.length;
// Otherwise, add the current value
// Will be undefined if at end of array so add zero
} else {
sum += +currentValue || 0;
}
// Increment i
i++;
}
return sum;
}
document.write(
'balance sequential 1: ' +
balance([1,[2,1,[1,2,-1],[1]],1,[2,1]]) // 11
+ '<br>balance sequential 2: ' +
balance([1,2,[3,4],5]) // 15
);
/* Sum the values of nested arrays. Only checks if values are arrays,
** otherwise assumes they're numbers
**
** #param {Array} arr - array of numbers to process, may have
** nested arrays of numbers
** #returns {number} - sum of values or NaN if arr is not an Array
*/
function balanceLoop(arr) {
if (!Array.isArray(arr)) return NaN;
for (var value, total=0, i=0, iLen=arr.length; i<iLen; i++) {
value = arr[i];
total += Array.isArray(value)? balanceLoop(value) : value;
}
return total;
}
document.write(
'<br>balanceLoop 1: ' +
balanceLoop([1,[2,1,[1,2,-1],[1]],1,[2,1]]) // 11
+ '<br>balanceLoop 2: ' +
balanceLoop([1,2,[3,4],5]) // 15
);
A simple recursive function:
function balance(arr, total) {
total = total || 0;
if (arr.length === 0) return total;
var head = arr[0];
if (typeof head === 'number') {
return balance(arr.slice(1), total += head);
} else {
return balance(head, total);
}
}
balance([1, [2, 1, 3, [43, 2]]])); // 52
DEMO
I would probably solve this using a recursive reduce, in the following manner:
function balance(arr) {
return arr.reduce(function(sum,item) {
return sum + (item instanceof Array ? balance(item) : item);
}, 0);
};
balance([1,[2,1,[1,2,-1],[1]],1,[2,1]]); // 11
If you don't mind the overhead, you could of course do this:
Number.prototype.balance = function() { return this; };
Array.prototype.balance = function() { return this.reduce(function(a,b) { return a + b.balance(); }, 0); }
[1,[2,1,[1,2,-1],[1]],1,[2,1]].balance(); // 11

depth first traversal of a graph - javascript

I am trying to learn graphs well and implemented the following depth-first search in javascript. The DFS function is working ok, but the checkRoutes function is the source of my troubles. The checkRoutes function accepts two inputs and returns true if there is a possible path between two nodes/vertices, and false if not. it does this by starting at a node, checking the adjacency list, and then checking the adjacency lists of every item in the adjacency list via recursion.
My solution works for only one case - when you check two vertices once, but due to the way I'm storing the possibleVertices array globally, "possibleVertices" doesn't get cleared out each time. how could I push and store to the "possibleToVisit" array inside "checkRoute" instead of globally in this class? Would it be better to have this array stored on the constructor?
var possibleToVisit = [];
function dfs(v) {
this.marked[v] = true;
if (this.adj[v] !== undefined) {
console.log("visited vertex " + v);
}
for (var i = 0; i < this.adj[v].length; i++) {
var w = this.adj[v][i];
if (!this.marked[w]) {
possibleToVisit.push(w)
this.dfs(w);
}
}
console.log(possibleToVisit);
}
function checkRoute(v, v2) {
this.dfs(v);
if (possibleToVisit.indexOf(v2) === -1) {
return false;
}
return true;
}
g = new Graph(5);
g.addEdge(0, 1);
g.addEdge(0, 2);
g.addEdge(1, 3);
g.addEdge(2, 4);
// g.showGraph();
// g.dfs(0);
console.log(g.checkRoute(0, 4));//true
console.log(g.checkRoute(0, 5));//false
https://jsfiddle.net/youngfreezy/t1ora6ab/3/#update
You can write a DFS "starter" function, which will reset all variables, and return something if necessary:
function Graph(v) {
this.startDfs = startDfs;
this.possibleToVisit = [];
}
// ...
function startDfs(v) {
this.possibleToVisit = []; // here, you can reset any values
this.dfs(v);
return true; // here, you can return a custom object containing 'possibleToVisit'
}
And call it only using startDfs:
function checkRoute(v, v2) {
this.startDfs(v);
if (this.possibleToVisit.indexOf(v2) === -1) {
return false;
}
return true;
}
Here is the updated JSFiddle.
Arrays in Javascript get passed as reference, so something like
function fill(a,l){
for(var i = 0;i<l;i++)
a.push(i + 10);
}
function check(idx, max){
var arr = [];
fill(arr,max);
console.log(arr[idx]); // 14
}
check(4,10)
would work and everytime check gets called arr is fresh and clean.
You can use a marked[] array (which is filled up during the dfs() call) to determine whether a particular vertex can be reached from a known vertex s.
Please take a look at the depth first search implementation in the following library:
https://github.com/chen0040/js-graph-algorithms
It provides an object oriented approach to the graph creation as well as the depth first search algorithm.
The sample code for its depth first search algorithm is given here:
var jsgraphs = require('js-graph-algorithms');
var g = new jsgraphs.Graph(6);
g.addEdge(0, 5);
g.addEdge(2, 4);
g.addEdge(2, 3);
g.addEdge(1, 2);
g.addEdge(0, 1);
g.addEdge(3, 4);
g.addEdge(3, 5);
g.addEdge(0, 2);
var starting_vertex = 0;
var dfs = new jsgraphs.DepthFirstSearch(g, starting_vertex);
for(var v=1; v < g.V; ++v) {
if(dfs.hasPathTo(v)) {
console.log(s + " is connected to " + v);
console.log("path: " + dfs.pathTo(v));
} else {
console.log('No path from ' + s + ' to ' + v);
}
}

Counting in binary

I'm only learning to program and was trying to make a program to count in binary.
I made a function that could convert the provided decimal to binary and it looks to be working just ok, but when I try to count upwards using a for loop my browser freezes and I can't understand why. Using a similar while loop produces the result I needed.
The problem is right at the bottom commented out. Please help figure out what I'm doing wrong here.
Here's my code:
function isOdd(num) {return num % 2};
var toBinary = function (number) {
ints = [];
binary = [];
ints.push(Math.floor(number));
while (number >= 1) {
number = (Math.floor(number))/2;
ints.push(Math.floor(number));
}
for (i=ints.length-1;i>=0;i--) {
if (isOdd(ints[i])) {
binary.push(1);
} else {
binary.push(0);
}
}
if (binary[0] === 0) {
binary.splice(0,1);
}
return binary;
};
var count = 0;
while (count <= 50) {
console.log(toBinary(count));
count++;
}
/*
for (i=1;i<=50;i++) {
console.log(toBinary(i));
}
*/
Use for (var i=ints.length-1;i>=0;i--) and for (var i=1;i<=50;i++), otherwise i will be a global variable and it will be overwritten inside toBinary.
You haven't declared i in the toBinary function, hence i is redefined on every call of toBinary in the last loop, and i will never reach 50.
Use var to declare variables like so:
var toBinary = function (number) {
var ints = [],
binary = [],
i;
:
}

Pick random property from a Javascript object

Suppose you have a Javascript object like:
{cat: 'meow', dog: 'woof', snake: 'hiss'}
Is there a more concise way to pick a random property from the object than this long winded way I came up with:
function pickRandomProperty(obj) {
var prop, len = 0, randomPos, pos = 0;
for (prop in obj) {
if (obj.hasOwnProperty(prop)) {
len += 1;
}
}
randomPos = Math.floor(Math.random() * len);
for (prop in obj) {
if (obj.hasOwnProperty(prop)) {
if (pos === randomPos) {
return prop;
}
pos += 1;
}
}
}
The chosen answer will work well. However, this answer will run faster:
var randomProperty = function (obj) {
var keys = Object.keys(obj);
return obj[keys[ keys.length * Math.random() << 0]];
};
Picking a random element from a stream
function pickRandomProperty(obj) {
var result;
var count = 0;
for (var prop in obj)
if (Math.random() < 1/++count)
result = prop;
return result;
}
I didn't think any of the examples were confusing enough, so here's a really hard to read example doing the same thing.
Edit: You probably shouldn't do this unless you want your coworkers to hate you.
var animals = {
'cat': 'meow',
'dog': 'woof',
'cow': 'moo',
'sheep': 'baaah',
'bird': 'tweet'
};
// Random Key
console.log(Object.keys(animals)[Math.floor(Math.random()*Object.keys(animals).length)]);
// Random Value
console.log(animals[Object.keys(animals)[Math.floor(Math.random()*Object.keys(animals).length)]]);
Explanation:
// gets an array of keys in the animals object.
Object.keys(animals)
// This is a number between 0 and the length of the number of keys in the animals object
Math.floor(Math.random()*Object.keys(animals).length)
// Thus this will return a random key
// Object.keys(animals)[0], Object.keys(animals)[1], etc
Object.keys(animals)[Math.floor(Math.random()*Object.keys(animals).length)]
// Then of course you can use the random key to get a random value
// animals['cat'], animals['dog'], animals['cow'], etc
animals[Object.keys(animals)[Math.floor(Math.random()*Object.keys(animals).length)]]
Long hand, less confusing:
var animalArray = Object.keys(animals);
var randomNumber = Math.random();
var animalIndex = Math.floor(randomNumber * animalArray.length);
var randomKey = animalArray[animalIndex];
// This will course this will return the value of the randomKey
// instead of a fresh random value
var randomValue = animals[randomKey];
If you are capable of using libraries, you may find that Lo-Dash JS library has lots of very useful methods for such cases. In this case, go ahead and check _.sample().
(Note Lo-Dash convention is naming the library object _.
Don't forget to check installation in the same page to set it up for your project.)
_.sample([1, 2, 3, 4]);
// → 2
In your case, go ahead and use:
_.sample({
cat: 'meow',
dog: 'woof',
mouse: 'squeak'
});
// → "woof"
You can just build an array of keys while walking through the object.
var keys = [];
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
keys.push(prop);
}
}
Then, randomly pick an element from the keys:
return keys[keys.length * Math.random() << 0];
If you're using underscore.js you can do:
_.sample(Object.keys(animals));
Extra:
If you need multiple random properties add a number:
_.sample(Object.keys(animals), 3);
If you need a new object with only those random properties:
const props = _.sample(Object.keys(animals), 3);
const newObject = _.pick(animals, (val, key) => props.indexOf(key) > -1);
You can use the following code to pick a random property from a JavaScript object:
function randomobj(obj) {
var objkeys = Object.keys(obj)
return objkeys[Math.floor(Math.random() * objkeys.length)]
}
var example = {foo:"bar",hi:"hello"}
var randomval = example[randomobj(example)] // will return to value
// do something
Another simple way to do this would be defining a function that applies Math.random() function.
This function returns a random integer that ranges from the 'min'
function getRandomArbitrary(min, max) {
return Math.floor(Math.random() * (max - min) + min);
}
Then, extract either a 'key' or a 'value' or 'both' from your Javascript object each time you supply the above function as a parameter.
var randNum = getRandomArbitrary(0, 7);
var index = randNum;
return Object.key(index); // Returns a random key
return Object.values(index); //Returns the corresponding value.
A lot of great answers here, so let me just try to spread the awareness of the bitwise NOT (~) operator in its double-trouble variant (which I'm pretty sure I learned about on StackOverflow, anways).
Typically, you'd pick a random number from one to ten like this:
Math.floor(Math.random()*10) + 1
But bitwise operation means rounding gets done faster, so the following implementation has the potential to be noticeably more performant, assuming you're doing enough truckloads of these operations:
~~(Math.random()*10) + 1

Categories

Resources