Javascript JSON comparison - javascript

I am trying to build a webapp that gets data from server and shows it to user. Script gets data from server every 10 seconds and if data has changed it alerts user. This is the code I'm using now, but it alerts every 10 second whether the data has changed or not.
So how do I need to alter my scipt to make it compare the old JSON and the new JSON and see if they are different, and if they are show alert before updating data shown to user?
$('#ListPage').bind('pageinit', function(event) {
getList1();
});
setInterval ( "getList1()", 10000 );
var old = "";
function getEmployeeList1() {
$.getJSON(serviceURL + 'getemployees.php?' + formArray, function(data) {
if(data != old){ // data from the server is not same as old
$('#nollalista li').remove();
keikka = data.key;
$.each(keikka, function(index, lista) {
$('#nollalista').append('<li><a href="employeedetails.html?id=' + lista.IND + '">' +
'<h4>' + lista.OSO + '</h4>' +
'<p>' + lista.AIKA + '</p>' +'</a></li>');
});
$('#nollalista').listview('refresh');
if(old != "")
alert("New data!");
old = data;
}
});
}

A very easy (but kind of lame) solution is comparing the string representations:
if(JSON.stringify(a) != JSON.stringify(b)) { ... }

Your code alerts every 10 sec, because your comparison
if(data != old){ // data from the server is not same as old
returns true everytime.
You can use this library to compare json in javascript
https://github.com/prettycode/Object.identical.js
and modify the comparison to
if(!Object.identical(data,old)){ // data from the server is not same as old
usage:
var a = { x: "a", y: "b" },
b = { x: "a", y: "b" },
c = { y: "b", x: "a" },
d = { x: "Chris", y: "Prettycode.org", developerYears: [1994, 2011] },
e = { y: "Prettycode.org", developerYears: [1994, 2011], x: "Chris" };
f = { y: "Prettycode.org", developerYears: [2011, 1994], x: "Chris" };
console.log(Object.identical(a, b)); // true (same properties and same property values)
console.log(Object.identical(a, c)); // true (object property order does not matter, simple)
console.log(Object.identical(d, e)); // true (object property order does not matter, complex)
console.log(Object.identical(d, f)); // false (arrays are, by definition, ordered)

Related

Translate aggregation operation in MongoDB to MapReduce

I've been trying to translate this query into MapReduce for a few days. Specifically, I need to figure out how many different cars have driven "N" kilometers.
Query:
db.adsb.group({
"key": {
"KM": true
},
"initial": {
"countCar": 0
},
"reduce": function(obj, prev) {
if (obj.Matricula != null) if (obj.Matricula instanceof Array) prev.countCar += obj.Matricula.length;
else prev.countCar++;
},
"cond": {
"KM": {
"$gt": 10000,
"$lt": 45000
}
}
});
Each document in Mongo has this form:
{
"_id" : ObjectId("5a8843e7d79a740f272ccc0a"),
"KM" : 45782,
"Matricula" : "3687KTS",
}
I'm trying to get something like:
/* 0 */
{
“KM” : 45000,
“total” : 634
}
/* 1 */
{
“KM” : 46000,
“total” : 784
}
My code is below, and it compiles but does not give me the expected results.
In particular, every time I enter 'reduce' it seems to reset all the values to 0, which prevents me from accumulating the registrations.
One of my problems is that when handling large amounts of information, the function must iterate several times ' reduce'.
I also don't know if it could be done that way, or I would need to return a list of car plates and their counter together in 'reduce'; and then in finalize add it all up.
// Map function
var m = function() {
if (this.KM > 10000 && this.KM < 45000) { // So that i can get KM grouped together by thousands (10000, 20000, 30000...)
var fl = Math.round(this.KM / 1000) * 1000;
var car = this.Matricula
emit (fl, car);
//print("map KM=" + fl + " Matricula= " + car);
}
};
// Reduce function
var r = function(key, values) {
var ya_incluido = false;
var cars_totales = 0;
var lista_car = new Array();
//print( key + " ---- " + values);
for (var i=0; i < values.length;i++)
{
for (var j=0; j < lista_car.length;j++)
{
if(values[i] == lista_car[j]) { //If it is already included, don't aggregate it
ya_incluido = true;
}
} if (ya_incluido != true) { //If it is not included, add it to lista_av list.
lista_car.push(values[i]);
} ya_incluido = false;
}
cars_totales = lista_av.length; //The number of distinct cars is equal to the lenght of the list we created
return cars_totales;
};
// Finalize function
var f = function(key,value) {
// Sum up the results?
}
db.runCommand( {
mapReduce: "dealer",
map: m,
reduce: r,
finalize: f,
out: {replace : "result"}
} );
I found the answer and a really good explanation here: https://stackoverflow.com/a/27532153/13474284
I found the answer and a really good explanation here: https://stackoverflow.com/a/27532153/13474284
I couldn't find a way to return in 'reduce' the same thing that came from ' map' . And since it was run several times, it only got the results of the last iteration. The way it appears in the link, the problem is solved without any difficulty.

Jasmine - how to write custom matcher to sum two numbers?

I'm using Jasmine 2.1.3 and trying to create a custom matcher to sum two numbers.
However I am getting:
Expected 24 not to equal 12
So far I have
it("is 24 for 24", function() {
result = simpleMath.sum_of(12,12); // gets 24
expect(result).toBeSumOf([12,12]);
});
and
beforeEach(function() {
simpleMath = new SimpleMath();
jasmine.addMatchers({
toBeSumOf: function (util, customEqualityTesters) {
return {
compare: function(actual, expected) {
// var passed = actual == expected // comparison example that worked
var passed = (actual[0]+actual[1]) == expected;
return {
pass: passed,
message: 'Expected ' + actual + (passed ? '' : ' not') + ' to equal ' + expected
};
}
};
}
});
});
Your actual and expected are the wrong way around, just add:
console.log(actual);
console.log(expected);
To your matcher and you'll see, you can use either format for the parameters 12, 12 or [12, 12] but for the former you'll need to add another parameter so the array format is probably preferable. You could of course use an object if that helps for more complex comparisons/matchers.
Working (array based) example:
describe("My custom test", function() {
it("should work", function() {
var result = 12 + 12;
expect(result).toBeSumOf([12, 12]);
});
});
and:
beforeEach(function () {
jasmine.addMatchers({
toBeSumOf: function () {
return {
compare: function (actual, expected) {
var passed = (actual == expected[0] + expected[1]);
return {
pass: passed,
message: 'Expected value ' + (expected[0] + expected[1]) + (passed ? '' : ' not') + ' equal to ' + actual
};
}
};
}
});
});
Gives:
Changing one of the values gives:

Is it possible to pass object as parameter?

var obj = {
name1: 1,
name2: 2
}
function myF(obj) {
console.log(obj.name1) // by idea it must return 1
};
myF(obj)
Does anybody know how to pass object in function?
Yes objects make great parameters.
var p1 = {
name: "Tom",
age: 23,
isMale: true
};
var p2 = {
name: "Alicia",
age: 21,
isMale: false
};
var p3 = {
name: "Landon",
age: 1,
isMale: true
};
function greeting(person) {
var str = '';
str += 'Hello my name is ';
str += person.name + ' ';
str += 'I'm a ' + person.age + ' year old ';
if (person.isMale) {
str += age > 18 ? 'man' : 'boy';
} else {
str += age > 18 ? 'woman' : 'girl';
}
if (person.age < 3) {
str = 'Bah'
}
console.log(str);
};
greeting(p1); // 'Hello my name is Tom I'm a 23 year old man';
greeting(p2); // 'Hello my name is Alicia I'm a 21 year old woman;
greeting(p3); // 'Bah';
Objects are good for when you have a grouping of values that belong together and you don't want to pass them in individually (If they belong together they rarely should be passed on their own.)
This is very common practice. Many libraries will utilize a config object so one does not have to specify multiple params
Example:
function makeSquare(height, width, color, border)
Could be easier represented with
function makeSquare(config)
This would make it easier for users to leave out some parameters, say you wanted to makeSquare without a border you would not need to include the border param if you are passing and object.
With parameters
makeSquare(10, 20, red, null)
with Obj
config = {
height: 10,
width: 10,
color: 'red'
};
makeSquare(config);
If you had an extensive amount of configuration options you could see where this may save quite a bit of development time and space

How to create a dynamic array in Javascript?

I need to create the following array dynamically, for example:
var data = { point: [
{ x:5, y:8 },
{ x:8, y:10},
]};
console.log(data.point[0].x); // 5 n=0
console.log(data.point[1].y); // 10 n=1
At some point my application needs to expand the array to more than 2 items (n=0, n=1). Please let me know how to do that (i.e. n = 9 ).
You could use Array.push method to add element to an array.
var point = {x:1,y:1};
data.point.push(point);
you can use method 'push' like this code
var data = { point: [
{ x:5, y:8 },
{ x:8, y:10},
]};
console.log(data.point[0].x); // 5 n=0
console.log(data.point[1].y); // 10 n=1
data.point.push({x:4,y:3});
console.log(JSON.stringify(data.point));
You could do something like this:
var data = {'points' : []};
function addPoint(x, y) {
data.points.push({'x' : x, 'y' : y});
}
function getPoint(index) {
return data.points[index];
}
addPoint(10, 20);
addPoint(5, 3);
var p = getPoint(1);
alert(p.x + ", " + p.y); //alerts => "5, 3"
This would work for any arbitrary number of points.
Update
To clear the array
function clearPoints() {
data.points = [];
}
Update 2
These little functions will work okay if you have a simple page. If this points handling is going to end up being part of a larger system, it may be better to do something like this:
var data = {
'points' : [],
addPoint : function(x, y) {
this.points.push({
'x' : x,
'y' : y
});
},
getPoint : function(index) {
return this.points[index];
},
clearPoints : function() {
this.points = [];
},
removePoint : function(index) {
this.points.splice(index, 1);
}
};
Example usage:
alert(data.points.length); // => 0
data.addPoint(1, 2);
data.addPoint(8, 12);
data.addPoint(3, 7);
alert(data.points.length); // => 3
var p = data.getPoint(2); //p = {x:3, y:7};
data.removePoint(1);
alert(data.points.length); // => 2
data.clearPoints();
alert(data.points.length); // => 0
It may allow you to keep your point handling a little cleaner and easier to use and update.
You can either use the push() function as stated, or add additional items to the array using an index, which is preferred in the Google Style Guide. The latter method does require that you have a pointer to the last index.
Note that since assigning values to an array is faster than using
push() you should use assignment where possible.
for(var i=lastIndex; i < numOfNewPoints; i++){
data.point[i] = {x:4, y:3};
}

Unordered function arguments in Javascript

Below is a regular function with named parameters:
function who(name, age, isMale, weight)
{
alert(name + ' (' + (isMale ? 'male' : 'female') + '), ' + age + ' years old, ' + weight + ' kg.');
}
who('Jack', 30, true, 90); //this is OK.
What I want to achive is; whether you pass the arguments in order or not; the function should produce a similar result (if not the same):
who('Jack', 30, true, 90); //should produce the same result with the regular function
who(30, 90, true, 'Jack'); //should produce the same result
who(true, 30, 'Jack', 90); //should produce the same result
This enables you to pass a list of arguments in any order but still will be mapped to a logical order. My approach up to now is something like this:
function who()
{
var name = getStringInArgs(arguments, 0); //gets first string in arguments
var isMale = getBooleanInArgs(arguments, 0); //gets first boolean in arguments
var age = getNumberInArgs(arguments, 0); //gets first number in arguments
var weight = getNumberInArgs(arguments, 1); //gets second number in arguments
alert(name + ' (' + (isMale ? 'male' : 'female') + '), ' + age + ' years old, ' + weight + ' kg.');
}
There is a little problem here; functions such as getStringInArgs() and getNumberInArgs() go through all the arguments each time to find the arg by type at the specified position. I could iterate through args only once and keep flags for the positions but then I would have to do it inside the who() function.
Do you think this approach is logical and the only way? Is there a better way to do it?
EDIT 1: Code above actually works. I just want to know if there is a better way.
EDIT 2: You may wonder if this is necessary or whether it makes sense. The main reason is: I'm writing a jQuery function which adds a specific style to a DOM element. I want this function to treat its arguments like shorthand CSS values.
Example:
border: 1px solid red;
border: solid 1px red; /*will produce the same*/
So; here is the real and final code upto now:
(function($){
function getArgument(args, type, occurrence, defaultValue)
{
if (args.length == 0) return defaultValue;
var count = 0;
for(var i = 0; i < args.length; i++)
{
if (typeof args[i] === type)
{
if (count == occurrence) { return args[i]; }
else { count++; }
}
}
return defaultValue;
}
$.fn.shadow = function()
{
var blur = getArgument(arguments, 'number', 0, 3);
var hLength = getArgument(arguments, 'number', 1, 0);
var vLength = getArgument(arguments, 'number', 2, 0);
var color = getArgument(arguments, 'string', 0, '#000');
var inset = getArgument(arguments, 'boolean', 0, false);
var strInset = inset ? 'inset ' : '';
var sValue = strInset + hLength + 'px ' + vLength + 'px ' + blur + 'px ' + color;
var style = {
'-moz-box-shadow': sValue,
'-webkit-box-shadow': sValue,
'box-shadow': sValue
};
return this.each(function()
{
$(this).css(style);
});
}
})(jQuery);
Usage:
$('.dropShadow').shadow(true, 3, 3, 5, '#FF0000');
$('.dropShadow').shadow(3, 3, 5, '#FF0000', true);
$('.dropShadow').shadow();
I find using objects to be more straight-forward and less error prone in the future:
var person = {
name: 'Jack',
age: 30,
isMale: true,
weight: 90
};
who(person);
function who(person){
alert(person.name +
' (' + (person.isMale ? 'male' : 'female') + '), ' +
person.age + ' years old, ' +
person.weight + ' kg.');
}
That way when you come back years later you don't have to lookup to see if age was the first, second, or fifth number and is more descriptive of what you are trying to accomplish.
This seems unnecessarily complex, not just from the perspective of the function, which needs to reorder its arguments, but also from the perspective of whoever is calling. You say that the function can accept its paramters in any order, but that's not entirely true. Since your determination of which variable is which is based on type, it relies on each variable being a different type. The name and gender can be anywhere, but the numeric arguments have to be in a specific order. It also prevents someone from passing in "30" or "90", which are numbers but will be regarded as strings - confusing it with the name and not finding an age or weight.
You can cache the arguments of a specific type in the arguments array. This is a big hack, you could follow the same pattern with the other getTypeInArgs
function getNumberInArgs(args, index) {
if (!args.numbers) {
args.numbers = [];
for (var i=0; i < args.length; i++) {
// You have to implement isNumber
if ( isNumber (args[i]) ) {
args.numbers.push(args[i];
}
}
}
return args.numbers[index];
}
I've never heard of accepting arguments in any order, except for the implode function in PHP, and it's marked on its documentation page as a big hack for historical reasons. So I wouldn't do this. If the order is too confusing, I would use the approach of taking a literal object, as suggested by WSkid.
You could try copying the arguments array into something you can destructively update:
untested code: Edit: I think it works now.
function args_getter(their_arguments){
//copy arguments object into an actual array
//so we can use array methods on it:
var arr = Array.prototype.slice.call(their_arguments);
return function(type){
var arg;
for(var i=0; i<arr.length; i++){
arg = arr[i];
if(type == typeof arg){
arr.slice(i, 1);
return arg;
}
}
return "do some error handling here"
}
}
function foo(){
var args = args_getter(arguments);
var b1 = args('boolean');
var b2 = args('boolean');
var n1 = args('number');
console.log(n1, b1, b2);
}
//all of
// foo(1, true, false),
// foo(true, 1, false), and
// foo(true, false, 1)
// should print (1, true, false)
This is still O(N^2) since you go through the array every time. However this shouldn't be an issue unless your functions can receive hundreds of arguments.
I agree with Griffin. This cannot be done unless you limit the choices more than you have. As it is, you have a string, a boolean and two numbers. Without some more rules on what can be in what position, you cannot tell which number is which. If you're willing to make some rule about which number comes first or which number comes after some other argument, then you can sort it out. In general, I think this is a bad idea. It's much better (from the standpoint of good programming) to use an object like WSkid suggested.
Anyway, if you wanted to make a rule like the weight has to come after the age, then it could be done like this:
function findParm(args, type) {
for (var i = 0; i < args.length; i++) {
if (typeof args[i] == type) {
return(i);
}
}
return(-1);
}
function who(name, age, isMale, weight) {
// assumes all variables have been passed with the right type
// age is before weight, but others can be in any order
var _name, _age, _isMale, _weight, i;
var args = Array.prototype.slice.call(arguments);
_name = args[findParm(args, "string")]; // only string parameter
_isMale = args[findParm(args, "boolean")]; // only boolean parameter
i = findParm(args, "number"); // first number parameter
_age = args[i];
args.splice(i, 1); // get rid of first number
_weight = args[findParm(args, "number")]; // second number parameter
// you now have the properly ordered parameters in the four local variables
// _name, _age, _isMale, _weight
}
who("fred", 50, false, 100);
Working here in this fiddle: http://jsfiddle.net/jfriend00/GP9cW/.
What I would suggest is better programming is something like this:
function who(items) {
console.log(items.name);
console.log(items.age);
console.log(items.weight);
console.log(items.isMale);
}
who({name: "Ted", age: 52, weight: 100, isMale: true});
function who({name, age, isMale, weight})
{
alert(name + ' (' + (isMale ? 'male' : 'female') + '), ' + age + ' years old, ' + weight + ' kg.');
}
who({name:'Jack', age:30, isMale:true, weight90});
Taking parameters as an object, allows you to pass arguments in any order.
There is no way you can do this since you have arguments of the same type.
Unless age and weight have non-overlapping ranges, you can't do this. How are you supposed to distinguish between 30 and 60 for weight or age??
This code:
function who(items) { console.log(items.name); console.log(items.age); console.log(items.weight); console.log(items.isMale);}who({name: "Ted", age: 52, weight: 100, isMale: true});
That a previous posted sent seems sensible. But why make things complicated. My experience when people make things complicated things go wrong.
BTW - The solution above (as the previous posted gave) is similar to the Perl solution.

Categories

Resources