I am using a dataset that contains around 65k data. I am mapping over the dataset multiple times to massage the dataset. After obtaining the dataset in the required format, I am using map to do some computations with the price of the current item. But, whenever I return the current object, it contains the computation data of the previous object.
Whenever I log the data, it always shows the current object and the computations based on the current object. But, the returned object contains a previous object's data. Here is the route:
const {priceBands} = require('../utils/profitComputations');
let profitArray = [];
//calculating the price bands
profitArray = _.map(nfoArray, item=>{
console.log(item.cmp);
//returns the current market price; getting the correct value here
let priceBandVar = priceBands(Number(item.cmp));
console.log(priceBandVar);
//applying some algorithms; getting the correct value here
return {item: item.cmp, profitBand: priceBandVar};
//Here I find a mismatch between the parameter and the calculations
});
Here is the priceBands function in my 'utils/profitComputations':
const _ = require('lodash');
const priceBandInterval = {'-4':0, '-3':0, '-2':0, '-1':0, '0floor':0,'0ceil':0,'1':0, '2':0, '3':0, '4':0};
let priceBands = {};
module.exports = {
priceBands: function(price){
let factor = 0;
if(price>=10000){
factor = 100;
}else if (price>=1000 && price<10000){
factor = 50;
}else if (price>=500 && price<1000){
factor = 25;
}else if (price>=100 && price<500){
factor = 10;
}else if(price>=25 && price<100){
factor = 2;
}else{
factor = 0.5;
}
let priceCeil, priceFloor;
if((price%factor) == 0){
priceCeil = price + factor;
priceFloor = price - factor;
} else {
const remainder = price%factor;
priceCeil = price - remainder + factor;
priceFloor = price - remainder;
}
_.map(Object.keys(priceBandInterval), item=>{
if(parseInt(item)>0){
priceBands[item] = (parseInt(item)*factor) + priceCeil;
} else if (parseInt(item)<0){
priceBands[item] = (parseInt(item)*factor) + priceFloor;
} else {
priceBands['0floor'] = priceFloor;
priceBands['0ceil'] = priceCeil;
}
});
return priceBands;
}
}
I would appreciate if someone can share some valuable insights on what I am missing.
You must clone the variable priceBandVar because javaScript variables are called by reference. The following code is your answer:
profitArray = _.map(nfoArray, item => {
console.log(item.cmp);
//returns the current market price; getting the correct value here
let priceBandVar = priceBands(Number(item.cmp));
console.log(priceBandVar);
//applying some algorithms; getting the correct value here
return {
item: item.cmp,
profitBand: clone(priceBandVar)
};
//Here I find a mismatch between the parameter and the calculations
});
function clone(o) {
var ret = {};
Object.keys(o).forEach(function(val) {
ret[val] = o[val];
});
return ret;
}
Here is my code
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendMessage = functions.database.ref('/UserRequests/{uid}')
.onCreate((snap, context) => {
const position = snap.val();
var loc = [position.l[0], position.l[1]];
const db = admin.database();
const ref = db.ref('/DriversAvailable');
const drivers = new GeoFire(ref);
var data = [];
const pathId = context.auth.uid;
const ref1 = db.ref('/UserRequests/{pathId}');
console.log("UserID" + pathId);
ref.once('value').then(snapshot => {
snapshot.forEach(function (child) {
console.log(child.key + " key"); //This code gets executed afterwards.
var c = child.val();
var aaa = child.key;
var lat = c.l[0];
var lng = c.l[1];
var dist = getDistance(position.l[0], position.l[1], lat, lng);
console.log("dis" + lat + lng + "aaa" + dist);
data.push({
id: aaa,
dis: dist
});
});
return console.log("gotit");
});
var getDistance = function (lat1, lng1, lat2, lng2) {
var R = 6378137; // Earth’s mean radius in meter
var dLat = rad(lat2 - lat1);
var dLong = rad(lng2 - lng1);
var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(rad(lat1)) * Math.cos(rad(lat2)) *
Math.sin(dLong / 2) * Math.sin(dLong / 2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
var d = R * c;
return d; // returns the distance in meter
};
var rad = function (x) {
return x * Math.PI / 180;
};
data.sort(function (a, b) {
return a.dis - b.dis
});
var i = 0;
var n = data.length;
console.log("number" + n); //This code is executed first.
while (i < 2 && i <= n) {
i++;
var k = data[i].id;
const getdevicetokenpromise = db.ref(`/DriversAvailable/${k}/token`).once('value');
return getdevicetokenpromise.then(result => {
console.log(result.val());
var token = result.val();
const payload = {
data: {
uid: pathId
}
};
return admin.messaging().sendToDevice(token, payload)
.then((response) => {
return console.log("Successfully sent message:", response);
})
.catch((error) => {
console.log("Error sending message:", error);
});
});
}
console.log("hi");
});
I am deploying the above function in Firebase cloud. I have commented about which code is being executed first and which is executed afterwards. I couldn't get why this is happening.
The part which is executed afterwards is taking data from firebase and computing the distance between two points using the function getDistance. As it comes before the code below it, it should be executed first.
Firebase works with promises, whereby the result is either resolved or rejected.
that means that the result, in your case the data fetched, takes sometime. Since your code is not nested, any other functions are executed asyncronously
I suggest nesting what you need executed within the .then{} block, or decoupling the functionality and putting it in a separate function, then calling that function while passing relevant parameters, in this case the snapshot data
The call ref.on("value", callback) will be executed first. The callback however will be executed somewhere in the future.
In you case you are probably better of using once:
ref.once('value').then(snapshot => ...)
All other logic should live inside the then as it depends on the value in the snapshot:
return ref.once('value).then(snapshot => {
var data = []
...
snapshot.forEach(child => {
data.push(...)
})
...
// other code
})
I am trying to implement, in Javascript, a divide and conquer algorithm to calculate a Delanay triangulation, in order to obtain a Voronoi diagram. The coded is based on the C++ implementation described in Graphic Gems IV which, in turn, is based on the famous Guibas and Stolfi paper from 1985. It uses a Quad-Edge data structure.
The algorithm divides the set of points in half; then, it triangulates those parts separately; lastly it proceeds to "marry" the two halves.
The problem is that, well, it does not work. It gets stuck in a infinite recursion when "marrying" the two halves. I think the problem might be in the Quad-Edge structure itself, because the first edge's and its destination edge have the same coordinates and its dual and inverted rotation edge point to (0, 0).
Here is the code (the translation from C++ is not 100 %, I asked for help since I am still a JS noob):
//The data structure starts here.
var Edge = function (num, qe) {
var _this = this;
this.num = num;
this.qe = qe;
this.coord = new paper.Point();
this.sym = function () {
return (_this.num < 2) ? _this.qe[_this.num + 2] : this.qe[_this.num - 2];
};
this.oNext = function () {
return this.next;
};
this.setNext = function (next) {
this.next = next
};
this.rot = function () {
return (this.num < 3) ? _this.qe[_this.num + 1] : _this.qe[_this.num - 3];
};
this.invRot = function () {
return (_this.num > 0) ? _this.qe[_this.num - 1] : _this.qe[_this.num + 3];
};
this.oPrev = function () {
return _this.rot().oNext().rot();
};
this.dNext = function () {
return _this.sym().next.sym();
};
this.dPrev = function () {
return _this.invRot().oNext().invRot();
};
this.lNext = function () {
return _this.invRot().oNext().rot();
};
this.lPrev = function () {
return _this.oNext().sym();
};
this.rNext = function () {
return _this.rot().oNext().invRot();
};
this.rPrev = function () {
return _this.sym().oNext();
};
this.dest = function () {
return _this.sym().coord;
};
this.endPoints = function (or, de) {
this.coord = or;
this.sym().coord = de;
};
};
//The first edge always points to itself
//as in edge.oNext().coord === edge.coord
var QuadEdge = function () {
this.edges = new Array(4);
for (var i = 0; i < 4; i++) {
this.edges[i] = new Edge(i, this.edges);
}
this.edges[0].setNext(this.edges[0]);
this.edges[1].setNext(this.edges[3]);
this.edges[2].setNext(this.edges[2]);
this.edges[3].setNext(this.edges[1]);
};
//Constructs and returns a new QuadEdge.
function makeEdge() {
var qe = new QuadEdge();
return qe.edges[0];
}
//Helper function, returns twice of the area of the triangle formed
//by a, b and c. Negative if the triangle is clockwise.
function triArea(a, b, c) {
return (b.x - a.x) * (c.y - a.y) - (c.x - a.x) * (b.y - a.y);
}
//Tests if the point d is inside the circumcircle of the triangle formed by
//a, b, and c. As described by Guibas and Stolfi in their paper.
function inCircle(a, b, c, d) {
return (Math.pow(a.x, 2) + Math.pow(a.y, 2)) * triArea(b, c, d) -
(Math.pow(b.x, 2) + Math.pow(b.y, 2)) * triArea(a, c, d) +
(Math.pow(c.x, 2) + Math.pow(c.y, 2)) * triArea(a, b, d) -
(Math.pow(d.x, 2) + Math.pow(d.y, 2)) * triArea(a, b, d) > 0;
}
//Tests if triangle is in counterclockwise order.
function cClockwise(a, b, c) {
return triArea(a, b, c) > 0;
}
//Tests if point is left of the provided edge.
function leftOf(point, edge) {
return cClockwise(point, edge.coord, edge.dest());
}
//Tests if point is right of the provided edge.
function rightOf(point, edge) {
return cClockwise(point, edge.dest(), edge.coord);
}
//If a and b are distinct, splice will combine them; if not, it will
//separate them in two.
function splice(a, b) {
var alpha = a.oNext().rot();
var beta = b.oNext().rot();
var t1 = b.oNext();
var t2 = a.oNext();
var t3 = beta.oNext();
var t4 = alpha.oNext();
a.setNext(t1);
b.setNext(t2);
alpha.setNext(t3);
beta.setNext(t4);
}
function deleteEdge(e) {
splice(e, e.oPrev());
splice(e.sym(), e.sym().oPrev());
}
function connect(e1, e2) {
var e = makeEdge();
e.endPoints(e1.dest(), e2.coord);
splice(e, e1.lNext());
splice(e.sym(), e2);
return e;
}
//Fixed thanks to: http://www.rpenalva.com/blog/?p=74
function valid(e, basel) {
return rightOf(e.dest(), basel);
}
//This is the actual algorithm.
function divideAndConquer(vertices) {
if (vertices.length === 2) {
var a = makeEdge();
a.coord = vertices[0];
a.sym().coord = vertices[1];
return {right: a, left: a.sym()};
}
else if (vertices.length === 3) {
var a = makeEdge(), b = makeEdge();
splice(a.sym(), b);
a.coord = vertices[0];
b.coord = vertices[1];
a.sym().coord = b.coord;
b.sym().coord = vertices[2];
if (cClockwise(vertices[0], vertices[1], vertices[2])) {
connect(b, a);
return {right: a, left: b.sym()};
}
else if (cClockwise(vertices[0], vertices[2], vertices[1])) {
var c = connect(b, a);
return {right: c.sym(), left: c};
}
else
return {right: a, left: b.sym()};
}
else if (vertices.length >= 4) {
var half = Math.floor(vertices.length / 2);
var lObjects = divideAndConquer(vertices.slice(0, half));
var rObjects = divideAndConquer(vertices.slice(half, vertices.length));
var ldo = lObjects.right, ldi = lObjects.left;
var rdi = rObjects.right, rdo = rObjects.left;
while (true) {
if (leftOf(rdi.coord, ldi))
ldi = ldi.lNext();
else if (rightOf(ldi.coord, rdi))
rdi = rdi.rPrev();
else
break;
}
var basel = connect(rdi.sym(), ldi);
if (ldi.coord === ldo.coord)
ldo = basel.sym();
if (rdi.coord === rdo.coord)
rdo = basel;
while (true) {
var lcand = basel.sym().oNext();
if (valid(lcand, basel)) {
while (inCircle(basel.dest(), basel.coord, lcand.dest(), lcand.oPrev().dest())) {
var t = lcand.oNext();
deleteEdge(lcand);
lcand = t;
}
}
var rcand = basel.oPrev();
if (valid(rcand, basel)) {
while (inCircle(basel.dest(), basel.coord, rcand.dest(), rcand.oPrev().dest())) {
var t = rcand.oPrev();
deleteEdge(rcand);
rcand = t;
}
}
//This is the part where it gets stuck,
//it never reaches this condition.
if (!valid(lcand, basel) && !valid(rcand, basel)) {
break;
}
if (!valid(lcand, basel) || (valid(rcand, basel) && inCircle(lcand.dest(), lcand.coord, rcand.coord, rcand.dest()))) {
basel = connect(rcand, basel.sym());
}
else {
basel = connect(basel.sym(), lcand.sym());
}
}
return {right: ldo, left: rdo};
}
}
The point class is from PaperJS.
EDIT: set up a Codepen illustrating the problem; click in the output window to add the points. The recursions happens when the fourth point is added.
EDIT 2: fixed the infinite recursion, caused by the valid function, thanks to code found on Ruben Penalva's blog. But, the problem of the dual edge pointing to the origin still persists. That is:
edge.rot().coord === (0, 0)
That makes me think even more that the problem is with the QuadEdge structure itself.
EDIT 3: reading the code carefully for the nth time, I realized that the coordinates for the rotation and inversed rotation edge are never set. So I tried setting them by rotating the original edge. The output now draws something, though I'm pretty sure thats not a Delaunay triangulation. I updated the Codepen example with the progress.
I want to generate an Unique 5 digits ID + 784 at the begining, the constraint, I can execute the script only one time, and I have to avoid the first 100 numbers so It can't be 00100 and lower. Since I use timestamp and I can execute only my script one time how I can handle this ?
I did this it's maybe dumb but at least I tried.
ConcatedID();
function ConcatedID()
{
var uniqID = checkProtectedRange();
if (checkProtectedRange())
{
var BarcodeID = 784 + uniqID;
return BarcodeID;
}
else
checkProtectedRange();
}
function checkProtectedRange()
{
var uniqueID = GenerateUniqueID();
var checkRange = uniqueID.substr(uniqueID.length - 3);
var checkRangeINT = parseInt(checkRange);
if (checkRangeINT <= 100)
return (false);
else
return (true);
}
function GenerateUniqueID()
{
var lengthID = 5;
var timestamp = + new Date();
var ts = timestamp.toString();
var parts = ts.split("").reverse();
var id = "";
var min = 0;
var max = parts.length -1;
for (var i = 0; i < lengthID; ++i)
{
var index = Math.floor(Math.random() * (max - min + 1)) + min;
id += parts[index];
}
gs.log('Generate ID ' + id);
return id;
}
Without being able to track previously used IDs, you're left with chance to prevent duplicates. Your shenanigans with Date doesn't really change that. See the birthday problem.
Given that, just follow the most straight-forward method: Generate a random string consisting of five digits.
function GenerateUniqueID() {
return ('0000'+(Math.random() * (100000 - 101) + 101)|0).slice(-5);
}
Or, if you want just the final integer with constraints applied:
function GenerateUniqueID() {
return (Math.random() * (78500000 - 78400101) + 78400101)|0;
}
function CircleArea(Value) {
var Results = 3.14 * Value^2;
return Results;
}
So I want:
var Diameter = 30;
Diameter.CircleArea(); // Results 2826
Like:
var n = 30; n.toString() // Results 30
Syntax:
varName.myFunction();
You can but rarely should extend prototypes:
Number.prototype.circleArea = function() {
var value = this;
return Math.pow(value, 2) * Math.PI;
};
var num = 30;
console.log(num.circleArea()); // 2827.4333882308138
Your function accepts an argument .
So you will need to pass in Diameter like so :
CirclArea(Diameter)
Returns 2826