JavaScript: Recursive Async / Promise Based Function - javascript

I have the following recursive function that works beautifully when the output from transformItem is synchronous, but I've been having a very difficult time figuring out how to refactor it when transformItem returns a a promise and still get the same type of desired final object output.
function transformStack(target, stack){
var stackItem = stack.shift();//Copy Value
util.logData(_this.context, "Target:" + JSON.stringify(target) + " Stack:" + JSON.stringify(stack), 9);
switch(stackItem){
case "[]":
for(var x=0; x < target.length; x++){
//Copies values so not by Ref any more
var nextTarget = JSON.parse(JSON.stringify(target[x]));
if(stack.length > 0){
util.logData(_this.context, "Loop[]:" + JSON.stringify(nextTarget), 8);
target[x] = transformStack(nextTarget, JSON.parse(JSON.stringify(stack)));
} else {
util.logData(_this.context, "TransformTarget[]:" + JSON.stringify(nextTarget), 8);
target[x] = transformItem(nextTarget);
}
}
break;
default:
//Copies values so not by Ref any more
var nextTarget = JSON.parse(JSON.stringify(target[stackItem]));
if(stack.length > 0){
util.logData(_this.context, "Loop:" + JSON.stringify(nextTarget), 8);
target[stackItem] = transformStack(nextTarget, JSON.parse(JSON.stringify(stack)));
} else {
util.logData(_this.context, "TransformTarget:" + JSON.stringify(nextTarget), 8);
target[stackItem] = transformItem(nextTarget);
}
}
return target;
}
I created this base JSFiddle which illustrates this a little better on what I'm expecting:
https://jsfiddle.net/fxay76k8/9/
Can anyone help point me in the right direction? I've been looking at the following Stack Overflow post, but haven't been able to apply it properly to my flow:
JavaScript : Calling Recursive Functions With Promises
Thank-you for your help!
BTW, I'm using Q for the promises, but I'm pretty confident I can translate any other promise libraries over to what I need if someone can help me with the concepts here.

I was able to get this working with the following refactored code:
function transformStack(target, stack){
var stackItem = stack.shift();//Copy Value
var targetCopy = JSON.parse(JSON.stringify(target));
var stackCopy = JSON.parse(JSON.stringify(stack));
if(stackItem === "[]"){
return transformStackArray(targetCopy, stackCopy);
}
var nextTarget = targetCopy[stackItem];
if (stack.length > 0)
return transformStack(nextTarget, stackCopy).then(handleResponse.bind(this,target, stackItem));
else
return transformItem(nextTarget).then(handleResponse.bind(this,target, stackItem));
}
/**
* handleResponse - Helper function for merging objects for recursive function.
* #param original - The original passed value
* #param attribute - The name of the field to send
* #param updated - The updated value
* #returns {*} - Promise - Resolves to the merged object
*/
function handleResponse(original, attribute, updated){
original[attribute] = updated;
return q(original);
}
function transformStackArray(target, stack){
var deferred = q.defer();
var promises = [];
for(var x=0; x < target.length; x++){
var nextTarget = JSON.parse(JSON.stringify(target[x])); //Copies values so not by Ref any more
if(stack.length > 0){
promises.push(transformStack(nextTarget, JSON.parse(JSON.stringify(stack))));
} else {
promises.push(transformItem(nextTarget));
}
}
q.all(promises).then(function(updatedItem){
deferred.resolve(updatedItem);
}).catch(function(error){
deferred.reject(error);
});
return deferred.promise;
}
The big piece for me was wrapping my head around how to merge the objects as the new values go up the recursion. This is handles by handleResponse.
Now that I have this answer, how the linked StackOverflow relates makes a ton of sense but for some reason I had a really difficult time wrapping my head around this problem at first.

Related

How to get the next element on Map function?

I'm trying to make some coordinate plane functions on React native. But I'm having a problem that I don't know how to get the next element on my array.
This is my array:
[
{"M":["0","0"]},
{"H":"100"},
{"V":"0"},
{"H":"100"},
{"V":"100"},
{"H":"0"},
{"V":"100"},
{"H":"0"},
{"V":"0"},
]
This is my function:
const rotate = (pathArray, angle) =>{
if (angle > 0){
let vCordinate;
return pathArray.map((cordinate)=>{
if(Object.entries(cordinate)[0][0] == "M"){
let mCordinate = Object.entries(cordinate)[0][1];
mCordinate[0] = (parseInt(mCordinate[0]) * Math.cos(angle)) - (parseInt(mCordinate[1]) * Math.sin(angle));
mCordinate[1] = (parseInt(mCordinate[1]) * Math.cos(angle)) + (parseInt(mCordinate[0]) * Math.sin(angle));
return {[Object.entries(cordinate)[0][0]]: mCordinate};
}
//LOGIC TO GET NEXT ELEMENT
if(Object.entries(cordinate)[0][0] == "H"){
let hCordinate = Object.entries(cordinate)[0][1];
vCordinate = Object.entries(cordinate)[0][1]
return {[Object.entries(cordinate)[0][0]]: vCordinate};
}
if(Object.entries(cordinate)[0][0] == "V"){
return {[Object.entries(cordinate)[0][0]]: vCordinate};
}
})
}
return pathArray;
}
In this point I need to get the next element when I've hit "H".
How to do this?
The callback of map method accepts 3 arguments:
current item value;
current item index;
the array map was called upon.
So, you could use index to get next element value:
var newArray = myArray.map(function(value, index, elements) {
var next = elements[index+1];
// do something
});
or
var newArray = myArray.map(function(value, index) {
var next = myArray[index+1];
// do something
});
Note, the value of next variable may be undefined. Test the variable, if need, to prevent errors.

Object variable is undefined even though it's initialised

I have a Node project where I create a Unit and an AddGate:
var Unit = function(value, weight) {
this.value = value;
this.weight = weight;
}
var AddGate = function() {
this.sum_function = function(units) {
sum = 0;
for (unit in units)
sum += unit.value;
return sum;
};
};
AddGate.prototype = {
forward: function(units) {
this.units = units;
this.output_unit = new Unit(this.sum_function(units), 0.0);
return this.output_unit;
}
}
I create some Units, an AddGate, and a ForwardNeuron (guess what I'm making):
var in_1 = new Unit(1.0, 0.0);
...
var in_9 = new Unit(3.0, 0.0);
var add = new AddGate();
var forwardNeuron = function() {
a = add.forward({in_1, in_2, in_3, in_4, in_5, in_6, in_7, in_8, in_9});
};
forwardNeuron();
But for some reason, when in sum_function of AddGate, I can access each unit of units fine, but when I try to access unit.value, it says it's undefined, even though I've clearly initialised it. Am I missing something?
As the comments specify, for (let unit in units) will actually set unit as the key of the units object. You can correct this in a few ways such as using units[unit].value, but it would make more sense to me for the arguments to forward and sum_function to be an array. More or less as simple as:
add.forward([in_1, in_2, in_3, in_4, in_5, in_6, in_7, in_8, in_9]);
The sum would be a reduce operation on the array as in:
return units.reduce((sum, unit) => sum + unit.value, 0);
FYI 4castle's response worked for me - I wrote:
sum += units[unit].value;
That did the trick for me. Thanks again to 4castle and trincot for their speedy responses.
EDIT: The above is even better.

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);
}
}

Manipulating JSON with LoDash

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.

log recursion from jquery function

I'm trying to calculate a series with a recursive function and jQuery but I don't know how to log each recursion that the function is making so I could get the series members.
the code is the following:
$(document).ready(function () {
$("#button").click(function () {
var n = $("#number").val();
function series(n) {
if (n == 1) {
return 6;
} else {
return 0.5 * series(n - 1) + 4;
}
}
console.log(series(n));
});
});
The problem is that the function only logs the last series member. For example if n = 4 the series should be 6, 7, 7.5, 7.75.
The function only returns 7.75.
This is the series formula: series(n) = 0.5 * series(n - 1) + 4, if n = 1 then series(n) = 6;
Thank you!
It's not the most beautiful looking example, but if you take your code and then wrap it in another function with a results array. Then call your inner recursive function and store them to that array it can return the results as an array. You can then use a join to make it into a string to display using jQuery or console log it.
Fiddle: http://jsfiddle.net/mcfarljw/hPWuW/
function getSeriesArray(n) {
var results = [];
function series(n) {
if (n === 1) {
results.push(6);
return 6;
} else {
var result = 0.5 * series(n - 1) + 4;
results.push(result);
return result;
}
}
series(n);
return results;
}
Your use of console.log() is only accepting the output of the outermost series call. If you want to log every iteration you either need to log inside your series method or keep track of every result during the iterations in the series method and then log whatever you used to keep track.
This seems like homework so I wont give too much away, but it might help is used the inspector in browser to walked the execution and get a feel for how the code is flowing.
Try this
$(document).ready(function () {
$("#button").click(function () {
var n = $("#number").val();
function series(n) {
var val=6;
if (n != 1) {
val= 0.5 * series(n - 1) + 4;
}
console.log(val);
return val;
}
});
});

Categories

Resources