Compare 2 JSON (Array of objects) - javascript

Example structure of the JSON :
{ "array_name1" : [
{"name":"John","age":"18","group":"user","country":"UK","hobby":"series","sport":"football"},
{"name":"Ted","age":"20","group":"user","country":"US"}, ...]}
{ "array_name2" : [
{"name":"John","age":"18","group":"admin","country":"UK","hobby":"series","sport":"football"},
{"name":"Ted","age":"20","group":"user","country":"US", sport:"tennis"},
{"name":"David","age":"20","group":"user", sport:"tennis"},...]}
{ "array_name3" : [
{"name":"John","age":"18","group":"admin","country":"UK","hobby":"series","sport":"football"},
{"name":"David","age":"20","group":"user", sport:"tennis"},...]}
I have to compare 2 JSON Array of objects.
I need to compare objects with the same names in the 2 differents array of objects.
For example, I need to compare the array_name1 and array_name2 and I need to detect that a new object appeared in the array_name2. Also I need to detect that the value changed for group on John from user to admin.
If I need to compare the array_name2 and array_name3, I need to detect that the user Ted has been deleted on the array_name3.

Try like this..
var com = { "array_name1" : [
{"name":"John","age":"18","group":"user","country":"UK","hobby":"series","sport":"football"},
{"name":"Ted","age":"20","group":"user","country":"US"}]};
var com1 = { "array_name2" : [
{"name":"John","age":"18","group":"admin","country":"UK","hobby":"series","sport":"football"},
{"name":"Ted","age":"20","group":"user","country":"US", "sport":"tennis"},
{"name":"David","age":"20","group":"user", "sport":"tennis"}]}
var com2 = { "array_name3" : [
{"name":"John","age":"18","group":"admin","country":"UK","hobby":"series","sport":"football"},
{"name":"David","age":"20","group":"user", "sport":"tennis"}]};
var com3 = { "array_name3" : [
{"name":"John","age":"18","group":"admin","country":"UK","hobby":"series","sport":"football"},
{"name":"David","age":"20","group":"user", "sport":"tennis"}]};
console.log(com.array_name1 === com1.array_name2); // direct compare
function checkEqual(x,y) {
return JSON.stringify(x) === JSON.stringify(y);
}
console.log(checkEqual(com.array_name1, com1.array_name2));
console.log(checkEqual(com3.array_name3, com2.array_name3));

Related

How can i get the last item of array?

I have an array of objects. I need to render an information from the last item of the array and I try this:
<p>{leg.segments[leg.segments.length - 1].arrivalCity.caption}, </p>
but it keeps giving an error
Cannot read property 'caption' of undefined.
It seems that I can get items from arrays with length of 2 and more (or when specifically get leg.segments[0].arrivalCity.caption but get an error when try to render array with only one item. I can't understand what the problem is since it should just return leg.segments[leg.segment[0]] when array has just one item and be fine with it.
All objects have 'caption'-key, the only question is to get it from [0] or [1] index.
The array is a part of parsed JSON, here's one element I map through for an example:
"legs" :
[
{
"segments" :
[
{
"arrivalCity" :
{
"uid" : "LED",
"caption" : "ST PETERSBURG"
}
},
{
"arrivalCity" :
{
"uid" : "LON",
"caption" : "LONDON"
}
}
]
},
{
"segments" :
[
{
"arrivalCity" :
{
"uid" : "MOW",
"caption" : "MOSCOW"
}
}
]
}
]
I need to render LONDON in the first case and MOSCOW in the second. But I can get ST PETERSBURG and MOSCOW with <p>{leg.segments[0].arrivalCity.caption}</p> or an error with <p>{leg.segments[leg.segments.length - 1].arrivalCity.caption}</p>
It is unable to reproduce your problem. Please show us your array.
Assuming your array is,
var leg={segments:[{arrivalCity:{caption:"cap1"}}]};
Then if you run;
leg.segments[leg.segments.length - 1].arrivalCity.caption
You will see the expected output as 'cap1'
... quoting the OP ...
... <p>{leg.segments[0].arrivalCity.caption}</p> or ... <p>{leg.segments[leg.segments.length - 1].arrivalCity.caption}</p>
The misunderstanding might be due to not treating legs like an array. Thus, in order to always access the last arrivalCity item of each of a segments array, one has to iterate the legs array in first place.
Using the OP's sample data and implementing a basic render function which does iterate the legs array first and only with each iteration does access always the last item of the current segments array via e.g segmentList[segmentList.length - 1], as already done correctly by the OP, nothing will fail but the expected result will render ...
LONDON
MOSCOW
... example ...
function renderListOfLastArrivalCities(dataList) {
const listNode = document.querySelector('.last-arrivals');
dataList.forEach(({ segments: segmentList }) => {
//const lastSegmentItem = segmentList[segmentList.length - 1];
//const arrivalCity = lastSegmentItem && lastSegmentItem.arrivalCity;
const arrivalCity = segmentList[segmentList.length - 1]?.arrivalCity;
if (arrivalCity) {
const itemNode = document.createElement('li');
itemNode.textContent = arrivalCity.caption || '';
listNode.appendChild(itemNode);
}
})
}
const legs = [{
"segments": [{
"arrivalCity": {
"uid":"LED",
"caption":"ST PETERSBURG"
}
}, {
"arrivalCity": {
"uid":"LON",
"caption":"LONDON"
}
}]
}, {
"segments": [{
"arrivalCity": {
"uid":"MOW",
"caption":"MOSCOW"
}
}]
}];
renderListOfLastArrivalCities(legs);
<ul class="last-arrivals"></ul>
Seems like your leg.segments[leg.segments.length - 1] which i assume be as object that doesn't have arrivalCity property. If it has then you must be doing any typo or maybe your data shape is different.
Could you share your array with us to take a look over it.

javascript why does word return an array and word[0] undefined javascript

I'm trying to make my website bilingual.
so I would like to iterate my JS object translation. I can iterate it with this code :
for (var word of translation) {
console.log(word);
}
but then I get this:
from the moment I use this code I undefined
for (var word of translation) {
console.log(word[0]);
}
this is my object model
translation = [
{ English : [ ["English" , "engels"], ["lblEng",""] ]},
{dutch : [["dutch" , "nederlands"], ["lblNl",""]]},
{ second : [["second","seconde"], ["sec",""]]},
{minut : [["minut", "minut"],["min",""]]},
{ hour : [["hour","uur"],["h",""]]},
{ day :[ ["day", "dag"],["d",""]]},
{ to : [["to", "naar"],["to",""]]},
{ from : [["from", "van"],["from",""]]}
]
for...of interates over the values in your array, i.e. the objects. For example the first iteration, word = { English : [ ["English" , "engels"], ["lblEng",""] ]}
So when you do word[0] its undefined as there is no 0 property in that word object
for (var word of translation) {
console.log(word[0]);
}
The variable word will have assigned an object as follow:
{ English : [ ["English" , "engels"], ["lblEng",""] ]}
So, word[0] return undefined because the objects don't have a property 0.
Probably, what you really want to do is the following:
const translation = [
{ English : [ ["English" , "engels"], ["lblEng",""] ]},
{dutch : [["dutch" , "nederlands"], ["lblNl",""]]},
{ second : [["second","seconde"], ["sec",""]]},
{minut : [["minut", "minut"],["min",""]]},
{ hour : [["hour","uur"],["h",""]]},
{ day :[ ["day", "dag"],["d",""]]},
{ to : [["to", "naar"],["to",""]]},
{ from : [["from", "van"],["from",""]]}
];
for (let word of translation) {
// get the keys and values and loop over them.
Object.entries(word).forEach(([lang, values]) => {
//values[0] returns the first index, so you can access it as follow:
let [first] = values;
console.log(lang, first);
});
}
Thanks for al your reactions / answerds...
Of realy helped me forward, if took a while to respond becose I was making an ather partition of my web aplication.

Arrange array based on another array Javascript

I have reference array which has values ["a","b","c","d"] .and i have another array which is obtaining as part of API which is not very consistent format .i am pointing some examples below
case 1.`{
names : ["a"],
value : [ [0],[0],[2],[4],... ]
}`
case 2. `{
names : ["a","c"],
value : [ [0,2],[0,0],[2,3],[4,4],... ]
}`
the result could be in any combination
but my requirement is to assign the value of incoming result into another array
having index same as my reference array
for example : in
case 1
`
let finalArray = [["0",null,null,null],
["0",null,null,null],
["2",null,null,null].... ]
`
for case 2:
`let finalArray = [["0",null,"2",null],
["0",null,"0",null],
["2",null,"3",null].... ]
`
alse attaching a fiddle with my inputs below
jsfiddle link to problem
any suggestions?
i am trying to use minimal for loops for performance optimization
Hope this will be helpful.
var refArray = ["a","b","c","d"];
setTimeout(()=>{processResult({
"names" : ["a"],
"value" : [ [0],[0],[2],[4]]
})},2000);
setTimeout(()=>{processResult(
{
"names" : ["a","c"],
"value" : [ [0,2],[0,0],[2,3],[4,4]]
})},4000);
setTimeout(()=>{processResult(
{
"names" : ["d","c"],
"value" : [ [0,2],[0,0],[2,3],[4,4]]
})},6000);
function processResult (result) {
let res = result.value;
let resArray = res.map((el)=>{
let k=Array(refArray.length).fill(null);
refArray.forEach((e,i)=>{
let indx = result.names.indexOf(e);
if(indx>=0){
k[i] = el[indx]
}
});
return k;
})
console.log("result",resArray)
}
Below is what I could think of that would require least iterations.
var refArray = ["a", "b", "c", "d"];
setTimeout(()=>{processResult({
"names" : ["a"],
"value" : [ [0],[0],[2],[4]]
})},2000);
setTimeout(()=>{processResult(
{
"names" : ["a","c"],
"value" : [ [0,2],[0,0],[2,3],[4,4]]
})},4000);
setTimeout(()=>{processResult(
{
"names" : ["d","c"],
"value" : [ [0,2],[0,0],[2,3],[4,4]]
})},6000);
function processResult(result) {
//This map will contain max names matched in the result
var maxItemsFromResult = {};
//Find the indexes in refArray and fill map
//e.g. 1st- {0:0}, 2nd - {0:0, 1:2}, 3rd - {0:3, 1:2}
result.names.forEach((item, index) => {
let indexFound = refArray.indexOf(item);
if (indexFound > -1) {
maxItemsFromResult[index] = indexFound;
}
});
//for performance if no key matched exit
if (Object.keys(maxItemsFromResult).length < 1) {
return;
}
//This will be final result
let finalArray = [];
//Because finalArray's length shuld be total items in value array loop through it
result.value.forEach((item, itemIndex) => {
//Create a row
let valueArray = new Array(refArray.length).fill(null);
//Below will only loop matched keys and fill respective position/column in row
//i'm taking all the matched keys from current value[] before moving to next
Object.keys(maxItemsFromResult).forEach((key, index) => {
valueArray[maxItemsFromResult[key]] = item[index];//get item from matched key
});
finalArray.push(valueArray);
});
console.log(finalArray);
return finalArray;
}

Create an array of Objects from JSON

I have a JSON file like below:
[
{"fields":{category_class":"CAT2",category_name":"A"},"pk":1 },
{"fields":{category_class":"CAT1",category_name":"B"},"pk":2 },
{"fields":{category_class":"CAT1",category_name":"C"},"pk":3 },
{"fields":{category_class":"CAT2",category_name":"D"},"pk":4 },
{"fields":{category_class":"CAT3",category_name":"E"},"pk":5 },
{"fields":{category_class":"CAT1",category_name":"E"},"pk":6 },
]
I want to create an array of objects from the above JSON which will have two properties. i) CategoryClass ii) CategoryNameList. For example:
this.CategoryClass = "CAT1"
this.CategoryNameList = ['B','C','E']
Basically i want to select all categories name whose category class is CAT1 and so forth for other categories class. I tried this:
var category = function(categoryClass, categoryNameList){
this.categoryClass = categoryClass;
this.categoryList = categoryNameList;
}
var categories = [];
categories.push(new category('CAT1',['B','C','E'])
Need help.
You can use a simple filter on the array. You have a few double quotes that will cause an error in you code. But to filter only with CAT1 you can use the filter method
var cat1 = arr.filter( value => value.fields.category_class === "CAT1");
I would suggest this ES6 function, which creates an object keyed by category classes, providing the object with category names for each:
function groupByClass(data) {
return data.reduce( (acc, { fields } ) => {
(acc[fields.category_class] = acc[fields.category_class] || {
categoryClass: fields.category_class,
categoryNameList: []
}).categoryNameList.push(fields.category_name);
return acc;
}, {} );
}
// Sample data
var data = [
{"fields":{"category_class":"CAT2","category_name":"A"},"pk":1 },
{"fields":{"category_class":"CAT1","category_name":"B"},"pk":2 },
{"fields":{"category_class":"CAT1","category_name":"C"},"pk":3 },
{"fields":{"category_class":"CAT2","category_name":"D"},"pk":4 },
{"fields":{"category_class":"CAT3","category_name":"E"},"pk":5 },
{"fields":{"category_class":"CAT1","category_name":"E"},"pk":6 },
];
// Convert
var result = groupByClass(data);
// Outut
console.log(result);
// Example look-up:
console.log(result['CAT1']);
Question : Basically i want to select all categories name whose category class is CAT1 and so forth for other categories class
Solution :
function Select_CatName(catclass,array){
var CatNameList=[]
$(array).each(function(){
if(this.fields.category_class==catclass)
CatNameList.push(this.fields.category_name)
})
return CatNameList;
}
This function return the Desired Category Name List, you need to pass desired catclass and array of the data , as in this case it's your JSON.
Input :
Above function calling :
Output :
Hope It helps.

Search a JavaScript object

I have a JavaScript object like this:
[{
name : "soccer",
elems : [
{name : "FC Barcelona"},
{name : "Liverpool FC"}
]
},
{
name : "basketball",
elems : [
{name : "Dallas Mavericks"}
]
}]
Now I want to search on this JavaScript object in the browser. The search for "FC" should give me something like this:
[
{name : "FC Barcelona"},
{name : "Liverpool FC"}
]
How to do this fast? Are there any JavaScript libs for this?
You might like using jLinq (personal project)
http://hugoware.net:4000/Projects/jLinq
Works like LINQ but for JSON and it allows you to extend it and modify it however you want to. There is already a bunch of prebuilt methods to check values and ranges.
Seeing as though the only helpful answers have been referencing third party libraries - here's your native javascript solution. For anyone that only wants a few lines of code rather than a stack:
The function:
Array.prototype.findValue = function(name, value){
var array = map(this, function(v,i){
var haystack = v[name];
var needle = new RegExp(value);
// check for string in haystack
// return the matched item if true, or null otherwise
return needle.test(haystack) ? v : null;
});
return array;
}
A native .map() function:
map = function(array, mapFunction) {
var newArray = new Array(array.length);
for(var i = 0; i < array.length; i++) {
newArray[i] = mapFunction(array[i]);
}
return newArray;
}
Your object:
(skimmed from your posted abject):
myObject = {
name : "soccer",
elems : [
{name : "FC Barcelona"},
{name : "Liverpool FC"}
]
},
{
name : "basketball",
elems : [
{name : "Dallas Mavericks"}
]
}
For usage:
(This will search your myObject.elems array for a 'name' matching 'FC')
var matched = myObject.elems.findValue('name', 'FC');
console.log(matched);
The result - check your console:
[Object, Object, findValue: function]
0: Object
name: "FC Barcelona"
__proto__: Object
1: Object
name: "Liverpool FC"
__proto__: Object
length: 2
__proto__: Array[0]
Try jOrder. http://github.com/danstocker/jorder
It's optimized for fast O(logn) search and sorting on large (thousands of rows) tables in JS.
As opposed to array iteration, which most of the answers here are based on, jOrder uses indexes to filter data. Just to give you an idea, free-text search on a 1000-row table completes about 100 times faster than iteration. The bigger the table, the better ratio you get.
However jOrder can't process the format of your sample data. But if you re-format it like this:
var teams =
[
{ sport : "soccer", team: "FC Barcelona" },
{ sport : "soccer", team: "Liverpool FC" },
{ sport : "basketball", team : "Dallas Mavericks"}
]
You can get the desired results by first setting up a jOrder table:
var table = jOrder(teams)
.index('teams', ['team'], { grouped: true, ordered: true, type: jOrder.text });
And then running a search on it:
var hits = table.where([{ team: 'FC' }], { mode: jOrder.startof });
And you'll get exactly the two rows you needed. That's it.
The straightforward way to do this is simply to iterate over every property of the object and apply a test function to them (in this case, value.contains("FC")).
If you want it to go faster, you'd either need to implement some kind of caching (which could be eagerly populated in the background ahead of any queries), or perhaps precalculate the result of various popular test functions.
You could do this with regular expressions performed against a serialized JSON string:
var jsonString = "[{ name : \"soccer\", elems : [ {name : \"FC Barcelona\"}"
+", {name : \"Liverpool FC\"}]},{name : \"basketball\",elems : ["
+"{name : \"Dallas Mavericks\"} ]}]";
var pattern = /\s*([\w\d_]+)\s*:\s*((\"[^\"]*(your pattern here)[^\"]*\")|(\'[^\']*(your pattern here)[^\']*\'))\s*/g;
var foundItems = [];
var match;
while(match = pattern.exec(jsonString)){
foundItems.push(match[0]);
}
var foundJSON = "[{" + foundItems.join("}, {") + "}]";
var foundArray = eval(foundJSON);
I haven't tested the loop part of this, but the Regex seems to be working well for me with simple tests in firebug.
In regards to AngularJS, you can do this:
var item = "scope-ng-model";
(angular.element('form[name="myForm"]').scope())[item] = newVal;

Categories