Im looking for a way to compare 2 json records on screen. The way i want is that, i want to show these 2 records side by side and mark the matched or unmatched properties.
Is there a library that does it already, and if not, how can i do it ??
Edit
My goal is to identify the same/different properties & to show them to users with different styles, rather than comparing the objects as a whole.
Someone made a jQuery plugin for this - jQuery.PrettyTextDiff.
https://github.com/arnab/jQuery.PrettyTextDiff
$("input[type=button]").click(function () {
$("#wrapper tr").prettyTextDiff({
cleanup: $("#cleanup").is(":checked")
});
});
JSFiddle
Here is a quick JavaScript function to help you compare the to JSON strings.
First, it checks that they have same number of properties, then compares that they have the same properties (by name) and then it compares the values.
You may want to tweak the value comparison (to allow for undefined or null).
Hope it is a good starter for you.
<script type="text/javascript">
var so = {}; // stackoverflow, of course.
so.compare = function (left, right) {
// parse JSON to JavaScript objects
var leftObj = JSON.parse(left);
var rightObj = JSON.parse(right);
// add object properties to separate arrays.
var leftProps = [];
var rightProps = [];
for(var p in leftObj) { leftProps.push(p); }
for(var p in rightObj) { rightProps.push(p); }
// do they have the same number of properties
if (leftProps.length != rightProps.length) return false;
// is every right property found on the left
for (var r = 0; r < rightProps.length; r++) {
var prop = rightProps[r];
if (leftProps.indexOf(prop) < 0) {
return false;
}
}
// is every left property found on the right
for (var r = 0; r < leftProps.length; r++) {
var prop = leftProps[r];
if (rightProps.indexOf(prop) < 0) {
return false;
}
}
// do the values match?
for (var q = 0; q < leftProps.length; q++) {
var propname = leftProps[q];
var leftVal = leftObj[propname];
var rightVal = rightObj[propname];
if (leftVal != rightVal) {
return false;
}
}
return true;
}
</script>
Related
I'm trying to run a function only if the HTML in my two arrays match. Trying to change the arrays toString() changes the HTML in the arrays to "Object HTMLElement" which doesn't work. Using array.outerHTML() comes back with an error same with array.val(). I would rather not do a double for loop but I even tried that and still nothing. This should be pretty simple, what am I missing?
Context: I'm trying to make a Simon Game http://codepen.io/zjmitche/pen/MpWzop?editors=1010
//array content in console
var arrayOne = [section#three.square4, section#one.square4, section#three.square4, section#three.square4]
var arrayTwo = [section#three.square4, section#one.square4, section#three.square4, section#two.square4]
function nextCount() {
if (arrayOne === arrayTwo) {
//do something
{
}
Attempted for loop:
for (var i = 0; i < arrayOne.length; i++) {
for (var j = 0; j < arrayTwo.length; j++) {
if (arrayOne[i] != arrayTwo[j]) {
alert("test")
arraysMatch = false;
}
}
}
Well, for starters, you only need a single loop since if the lengths are different they clearly don't match. Then, use JSON.stringify to compare complex values easily:
arraysMatch = true;
if (arrayOne.length !== arrayTwo.length) {
arraysMatch = false;
} else {
for (var i = 0; i < arrayOne.length; i++) {
// Use JSON.stringify to get deterministic strings of non-primitives
var currVal1 = JSON.stringify(arrayOne[i]);
var currVal2 = JSON.stringigy(arraytwo[i]);
if (currVal1 !== currVal2) {
arraysMatch = false;
break; // No reason to keep going through the loop any more
}
}
}
I'm working on exercism question and am stuck on one of the jasmine-node based tests, which says that I should be able to generate 10000 random names without any clashes (e.g. 2 randomly generated names match). This is the test:
it('there can be lots of robots with different names each', function() {
var i,
numRobots = 10000,
usedNames = {};
for (i = 0; i < numRobots; i++) {
var newRobot = new Robot();
usedNames[newRobot.name] = true;
}
expect(Object.keys(usedNames).length).toEqual(numRobots);
});
What I think I need to do is:
Create an array to hold all the names (robotNames),
Each time a name is generated, check if it exists in the array,
If it does, generate another name,
If it doesn't, add it to the array.
And here is my code so far...
"use strict";
var robotNames = [];
var name;
var Robot = function() {
this.name = this.generateName();
};
Robot.prototype.generateName = function() {
var letters = "";
var alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
var numbers = "";
var digits = "0123456789";
// generate random characters for robot name...
for( var i=0; i < 2; i++ ) {
letters += alphabet.charAt(Math.floor(Math.random() * alphabet.length));
};
for( var i=0; i < 3; i++ ) {
numbers += digits.charAt(Math.floor(Math.random() * digits.length));
};
name = letters+numbers;
// Loop through array to check for duplicates
for(var i = 0; i < robotNames.length; i++) {
if (name == robotNames[i]) {
this.generateName();
return;
} else {
robotNames.push(name);
}
}
return name;
};
Robot.prototype.reset = function() {
this.name = this.generateName();
};
module.exports = Robot;
The test fails with an error message: "Expected 9924 to equal 10000."
The '9924' number is slightly different each time I run the test. I'm thinking this means the generateName function is eventually generating 2 matching random names. It seems as though my loop for checking duplicates is not being run and I'm not sure why.
I have tried a couple of different versions of the loop but with no success. So my questions is a) is my approach correct and there is something wrong with the syntax of my loop? or b) have I got the wrong idea about how to check for duplicates here?
Any pointers appreciated, thanks.
The problem is in this bit:
for(var i = 0; i < robotNames.length; i++) {
if (name == robotNames[i]) {
this.generateName();
return;
} else {
robotNames.push(name);
}
}
...you probably only want to push your name if NONE of the names fail to match. Here you're adding it to the list as soon as you find ONE that doesn't match. You want something more like:
for(var i = 0; i < robotNames.length; i++) {
if (name == robotNames[i]) {
return this.generateName();
}
}
robotNames.push(name);
(actually, combined with the fact that you weren't even returning the recursive call to this.generateName(), I'm not sure how your program could work...)
Find a library with an implementation for Sets. Collections.js is a good example.
One property of a set is that it doesn't have duplicates. So when you add a value to a set it will look for a duplicate and then add the value if no duplicate exists.
Here is my current filter function (quite incomplete)
$('input:checkbox.types').click(function(){
filterMarkers();
});
function filterMarkers() {
var checked = [];
$('input:checkbox.types:checked').each(function(){
checked.push($(this).val());
});
checked.sort();
var andor = '';
var andor = $('[name="and-or"]:checked').val();
if(andor == 1) {
// and
console.log(checked);
for (var i = 0; i < markers.length; i++) {
var types = markers[i]['types'].split(",");
types.sort();
console.log(types);
}
} else {
// or
}
}
Here is an image of what I have so far.
http://snag.gy/rKSTA.jpg
Let us say this for simplicity.
A = checked checkboxes
B = array with values of current item in map marker iteration / current iteration marker
I was able to get the values of the checked checkboxes. I was also able to convert the comma delimited string of each marker into an array. I would like to be able to check if B contains ANY of A (OR) and be able to check that B must contain A (AND).
Any ideas?
Here is the page in question for those wanting a 'feel' for what I am trying to accomplish. Thanks!
https://www.cablework.co/company
This page outputs what I have currently to console.
Once I can figure this out, I will then be able to hide/show markers based on the result.
Here's an example function. You would run test on every marker against the types array.
http://jsfiddle.net/q1k6e74d/5/
function test(op,types,marker){
var pass;
if(types.length === 0 || marker.length === 0){
return false;
}
if(op==="and"){
pass = true;
for(var i in types){
if( $.inArray(types[i],marker) == -1 ){
pass = false;
}
}
}else{ //or
pass = false;
for(var i in marker){
if( $.inArray(marker[i],types) !== -1 ){
pass = true;
}
}
}
return pass;
}
var a = [1,4];
var b = [1,5];
console.log("test a",a,"and b",b,test("and",a,b));
console.log("test a",a,"or b",b,test("or",a,b));
Could be shorter but it's easiest to understand this way I think.
(forgive me if I use slightly incorrect language - feel free to constructively correct as needed)
There are a couple posts about getting data from JSON data of siblings in the returned object, but I'm having trouble applying that information to my situation:
I have a bunch of objects that are getting returned as JSON from a REST call and for each object with a node of a certain key:value I need to extract the numeric value of a sibling node of a specific key. For example:
For the following list of objects, I need to add up the numbers in "file_size" for each object with matching "desc" and return that to matching input values on the page.
{"ResultSet":{
Result":[
{
"file_size":"722694",
"desc":"description1",
"format":"GIF"
},
{
"file_size":"19754932",
"desc":"description1",
"format":"JPEG"
},
{
"file_size":"778174",
"desc":"description2",
"format":"GIF"
},
{
"file_size":"244569996",
"desc":"description1",
"format":"PNG"
},
{
"file_size":"466918",
"desc":"description2",
"format":"TIFF"
}
]
}}
You can use the following function:
function findSum(description, array) {
var i = 0;
var sum = 0;
for(i = 0; i < array.length; i++) {
if(array[i]["desc"] == description && array[i].hasOwnProperty("file_size")) {
sum += parseInt(array[i]["file_size"], 10);
}
}
alert(sum);
}
And call it like this:
findSum("description1", ResultSet.Result);
To display an alert with the summation of all "description1" file sizes.
A working JSFiddle is here: http://jsfiddle.net/Q9n2U/.
In response to your updates and comments, here is some new code that creates some divs with the summations for all descriptions. I took out the hasOwnProperty code because you changed your data set, but note that if you have objects in the data array without the file_size property, you must use hasOwnProperty to check for it. You should be able to adjust this for your jQuery .each fairly easily.
var data = {};
var array = ResultSet.Result;
var i = 0;
var currentDesc, currentSize;
var sizeDiv;
var sumItem;
//Sum the sizes for each description
for(i = 0; i < array.length; i++) {
currentDesc = array[i]["desc"];
currentSize = parseInt(array[i]["file_size"], 10);
data[currentDesc] =
typeof data[currentDesc] === "undefined"
? currentSize
: data[currentDesc] + currentSize;
}
//Print the summations to divs on the page
for(sumItem in data) {
if(data.hasOwnProperty(sumItem)) {
sizeDiv = document.createElement("div");
sizeDiv.innerHTML = sumItem + ": " + data[sumItem].toString();
document.body.appendChild(sizeDiv);
}
}
A working JSFiddle is here: http://jsfiddle.net/DxCLu/.
That's an array embedded in an object, so
data.ResultSet.Result[2].file_size
would give you 778174
var sum = {}, result = ResultSet.Result
// Initialize Sum Storage
for(var i = 0; i < result.length; i++) {
sum[result[i].desc] = 0;
}
// Sum the matching file size
for(var i = 0; i < result.length; i++) {
sum[result[i].desc] += parseInt(result[i]["file_size"]
}
After executing above code, you will have a JSON named sum like this
sum = {
"description1": 20477629,
"description2": 1246092
};
An iterate like below should do the job,
var result = data.ResultSet.Result;
var stat = {};
for (var i = 0; i < result.length; i++) {
if (stat.hasOwnProperty(result[i].cat_desc)) {
if (result[i].hasOwnProperty('file_size')) {
stat[result[i].cat_desc] += parseInt(result[i].file_size, 10);
}
} else {
stat[result[i].cat_desc] = parseInt(result[i].file_size, 10);
}
}
DEMO: http://jsfiddle.net/HtrLu/1/
I have been searching online all day and I cant seem to find my answer. (and I know that there must be a way to do this in javascript).
Basically, I want to be able to search through an array of objects and return the object that has the information I need.
Example:
Each time someone connects to a server:
var new_client = new client_connection_info(client_connect.id, client_connect.remoteAddress, 1);
function client_connection_info ( socket_id, ip_address, client_status) {
this.socket_id=socket_id;
this.ip_address=ip_address;
this.client_status=client_status; // 0 = offline 1 = online
};
Now, I want to be able to search for "client_connection.id" or "ip_address", and bring up that object and be able to use it. Example:
var results = SomeFunction(ip_address, object_to_search);
print_to_screen(results.socket_id);
I am new to javascript, and this would help me dearly!
Sounds like you simply want a selector method, assuming I understood your problem correctly:
function where(array, predicate)
{
var matches = [];
for(var j = 0; j < array.length; j++)
if(predicate(j))
matches.push(j);
return matches;
}
Then you could simply call it like so:
var sample = [];
for(var j = 0; j < 10; j++)
sample.push(j);
var evenNumbers = where(sample, function(elem)
{
return elem % 2 == 0;
});
If you wanted to find a specific item:
var specificguy = 6;
var sixNumber = where(sample, function(elem)
{
return elem == specificguy;
});
What have you tried? Have you looked into converting the data from JSON and looking it up as you would in a dictionary? (in case you don't know, that would look like object['ip_address'])
jQuery has a function for this jQuery.parseJSON(object).
You're going to need to loop through your array, and stop when you find the object you want.
var arr = [new_client, new_client2, new_client3]; // array of objects
var found; // variable to store the found object
var search = '127.0.0.1'; // what we are looking for
for(var i = 0, len = arr.length; i < len; i++){ // loop through array
var x = arr[i]; // get current object
if(x.ip_address === search){ // does this object contain what we want?
found = x; // store the object
break; // stop looping, we've found it
}
}