Related
I am trying to compare 2 nested json objects arrays using lodash. Following example will return true even obj1 and obj2 have different number of objects inside the array.
Basically what I need to do is compare these 2 nested json objects arrays and if the arrays are identical then needs to return true else false
note : obj1 has price element and obj2 has countInStock which should not use to compare
Can anyone help me to solve this?
import _ from "lodash"
var obj1 = [{
"colour": {
"value": "Black",
"label": "Black"
},
"size": {
"value": "M",
"label": "M"
},
"price": "70"
},
{
"colour": {
"value": "Black",
"label": "Black"
},
"size": {
"value": "M",
"label": "M"
},
"price": "70"
},
{
"colour": {
"value": "Silver",
"label": "Silver"
},
"size": {
"value": "S",
"label": "S"
},
"price": "50"
},
{
"colour": {
"value": "Black",
"label": "Black"
},
"size": {
"value": "L",
"label": "L"
},
"price": "130"
}]
var obj2 = [{
"colour": {
"value": "Silver",
"label": "Silver"
},
"size": {
"value": "S",
"label": "S"
},
"countInStock": "3"
},
{
"colour": {
"value": "Black",
"label": "Black"
},
"size": {
"value": "M",
"label": "M"
},
"countInStock": "10"
},
{
"colour": {
"value": "Black",
"label": "Black"
},
"size": {
"value": "L",
"label": "L"
},
"countInStock": "3"
}]
var result = _.isEqual(
_.omit(obj1.sort, ['price']),
_.omit(obj2.sort, ['countInStock'])
);
console.log(result); // true
I am converting the object to tree node format using the below method
function getNodes(object) {
return Object
.entries(object)
.map(([key, value]) => value && typeof value === 'object' ?
{
value: key + value,
label: key,
children: getNodes(value)
} :
{
value: key + value,
label: key
}
);
}
The sample object is:
var object = {
"income-array": [{
"income": {
"id": "1234",
"currency": "dollar",
"details": {
"individual-income": [{
"name": "abcd",
"income": 100
}, {
"name": "xyz",
"income": 500
}]
}
}
}]
}
I am getting this result:
[{
"value": "income-array[object Object]",
"label": "income-array",
"children": [{
"value": "0[object Object]",
"label": "0",
"children": [{
"value": "income[object Object]",
"label": "income",
"children": [{
"value": "id1234",
"label": "id"
}, {
"value": "currencydollar",
"label": "currency"
}, {
"value": "details[object Object]",
"label": "details",
"children": [{
"value": "individual-income[object Object],[object Object]",
"label": "individual-income",
"children": [{
"value": "0[object Object]",
"label": "0",
"children": [{
"value": "nameabcd",
"label": "name"
}, {
"value": "income100",
"label": "income"
}]
}, {
"value": "1[object Object]",
"label": "1",
"children": [{
"value": "namexyz",
"label": "name"
}, {
"value": "income500",
"label": "income"
}]
}]
}]
}]
}]
}]
}]
I want to get the value property path from root to a particular node like the below. I am confused with how to append step by step path to value.
[{
"value": "income-array",
"label": "income-array",
"children": [{
"value": "['income-array'][0]",
"label": "0",
"children": [{
"value": "['income-array'][0]['income']",
"label": "income",
"children": [{
"value": "['income-array'][0]['income']['id']",
"label": "id"
}, {
"value": "['income-array'][0]['income']['currencydollar']",
"label": "currency"
}, {
"value": "['income-array'][0]['income']['details']",
"label": "details",
"children": [{
"value": "['income-array'][0]['income']['details']['individual-income']",
"label": "individual-income",
"children": [{
"value": "['income-array'][0]['income']['details']['individual-income'][0]",
"label": "0",
"children": [{
"value": "['income-array'][0]['income']['details']['individual-income'][0]['name']",
"label": "name"
}, {
"value": "['income-array'][0]['income']['details']['individual-income'][0]['income']",
"label": "income"
}]
}, {
"value": "['income-array'][0]['income']['details']['individual-income'][1]",
"label": "1",
"children": [{
"value": "['income-array'][0]['income']['details']['individual-income'][1]['name']",
"label": "name"
}, {
"value": "['income-array'][0]['income']['details']['individual-income'][1]['income']",
"label": "income"
}]
}]
}]
}]
}]
}]
}]
Can you please guide me how to resolve this? Thanks
The outer function needs to pass its own current absolute path (which is value in your code) to the inner function,
in order to let the inner function know the previous paths.
Notice the parentPath='' parameter and children: getNodes(value, currentPath) below
function getNodes(object, parentPath = "") {
return Object.entries(object).map(([key, value]) => {
const currentPath = parentPath + `[${key}]`;
return value && typeof value === "object"
? {
value: currentPath,
label: key,
children: getNodes(value, currentPath),
}
: {
value: currentPath,
label: key,
};
});
}
After that, run getNodes(object) in the browser and you will get a result like this.
[
{
"value": "[income-array]",
"label": "income-array",
"children": [
{
"value": "[income-array][0]",
"label": "0",
"children": [
{
"value": "[income-array][0][income]",
"label": "income",
"children": [
{
"value": "[income-array][0][income][id]",
"label": "id"
},
{
"value": "[income-array][0][income][currency]",
"label": "currency"
},
{
"value": "[income-array][0][income][details]",
"label": "details",
"children": [
{
"value": "[income-array][0][income][details][individual-income]",
"label": "individual-income",
"children": [
{
"value": "[income-array][0][income][details][individual-income][0]",
"label": "0",
"children": [
{
"value": "[income-array][0][income][details][individual-income][0][name]",
"label": "name"
},
{
"value": "[income-array][0][income][details][individual-income][0][income]",
"label": "income"
}
]
},
{
"value": "[income-array][0][income][details][individual-income][1]",
"label": "1",
"children": [
{
"value": "[income-array][0][income][details][individual-income][1][name]",
"label": "name"
},
{
"value": "[income-array][0][income][details][individual-income][1][income]",
"label": "income"
}
]
}
]
}
]
}
]
}
]
}
]
}
]
I have an array of json objects that I need grouped together by four to create an single object. Ultimately my goal is to use OPENJSON in SQL Sever to insert the values into a table with each object being a row.
It seems like it should be simple enough. I have been searching the web a lot and I have run across various things such as _.groupBy(), $.extend(true, {}, x, y); etc. But none of it seems to do quite what I want.
I have the following array of JSON objects:
[{"name":"locMLR","value":"6485183463415278686"},
{"name":"dayDate","value":"04/29/2019"},{"name":"intStps","value":"1"},
{"name":"intPkgs","value":"2"},
{"name":"locMLR","value":"6485183463415278686"},
{"name":"dayDate","value":"04/30/2019"},{"name":"intStps","value":"1"},
{"name":"intPkgs","value":"2"},
{"name":"locMLR","value":"6485183463415278686"},
{"name":"dayDate","value":"05/01/2019"},{"name":"intStps","value":"1"},
{"name":"intPkgs","value":"2"},
{"name":"locMLR","value":"6485183463415278686"},
{"name":"dayDate","value":"05/02/2019"},{"name":"intStps","value":"1"},
{"name":"intPkgs","value":"2"},
{"name":"locMLR","value":"6485183463415278686"},
{"name":"dayDate","value":"05/03/2019"},{"name":"intStps","value":"1"},
{"name":"intPkgs","value":"2"}]
I need the grouped as such:
Object {
{"name":"locMLR","value":"6485183463415278686"},
{"name":"dayDate","value":"04/29/2019"},
{"name":"intStps","value":"1"},
{"name":"intPkgs","value":"2"}
},
Object {
{"name":"locMLR","value":"6485183463415278686"},
{"name":"dayDate","value":"04/30/2019"},
{"name":"intStps","value":"1"},
{"name":"intPkgs","value":"2"}
},
Object {
{"name":"locMLR","value":"6485183463415278686"},
{"name":"dayDate","value":"05/01/2019"},{"name":"intStps","value":"1"},
{"name":"intPkgs","value":"2"}
}
You probably want a function like this chunk, which takes the chunk size and an array and groups the elements in chunks that size:
const chunk = (n, arr, res = []) => arr.length == 0
? res
: chunk (n, arr.slice(n), res.concat([arr.slice(0, n)]))
const arr = [{"name": "locMLR", "value": "6485183463415278686"}, {"name": "dayDate", "value": "04/29/2019"}, {"name": "intStps", "value": "1"}, {"name": "intPkgs", "value": "2"}, {"name": "locMLR", "value": "6485183463415278686"}, {"name": "dayDate", "value": "04/30/2019"}, {"name": "intStps", "value": "1"}, {"name": "intPkgs", "value": "2"}, {"name": "locMLR", "value": "6485183463415278686"}, {"name": "dayDate", "value": "05/01/2019"}, {"name": "intStps", "value": "1"}, {"name": "intPkgs", "value": "2"}, {"name": "locMLR", "value": "6485183463415278686"}, {"name": "dayDate", "value": "05/02/2019"}, {"name": "intStps", "value": "1"}, {"name": "intPkgs", "value": "2"}, {"name": "locMLR", "value": "6485183463415278686"}, {"name": "dayDate", "value": "05/03/2019"}, {"name": "intStps", "value": "1"}, {"name": "intPkgs", "value": "2"}]
console.log(chunk(4, arr))
There are plenty of alternative ways to write this. But this recursive solution is clean and straightforward, and if and when your JS engine performs tail-call optimization, it should be relatively efficient.
Update
If you want to do this without the recursive call, you can fold the array with reduce like this:
const chunk = (n, xs) => xs.reduce(
(a, x, i) => i % n == 0
? a.concat([[x]])
: a.slice(0, -1).concat([a.slice(-1)[0].concat(x)]),
[]
)
But to me that's quite a bit less readable.
You are not really grouping in the classic sense, I would do something like this:
const originalData = [
{
"name": "locMLR",
"value": "6485183463415278686"
},
{
"name": "dayDate",
"value": "04/29/2019"
}, {
"name": "intStps",
"value": "1"
},
{
"name": "intPkgs",
"value": "2"
},
{
"name": "locMLR",
"value": "6485183463415278686"
},
{
"name": "dayDate",
"value": "04/30/2019"
}, {
"name": "intStps",
"value": "1"
},
{
"name": "intPkgs",
"value": "2"
},
{
"name": "locMLR",
"value": "6485183463415278686"
},
{
"name": "dayDate",
"value": "05/01/2019"
}, {
"name": "intStps",
"value": "1"
},
{
"name": "intPkgs",
"value": "2"
},
{
"name": "locMLR",
"value": "6485183463415278686"
},
{
"name": "dayDate",
"value": "05/02/2019"
}, {
"name": "intStps",
"value": "1"
},
{
"name": "intPkgs",
"value": "2"
},
{
"name": "locMLR",
"value": "6485183463415278686"
},
{
"name": "dayDate",
"value": "05/03/2019"
}, {
"name": "intStps",
"value": "1"
},
{
"name": "intPkgs",
"value": "2"
}
];
const groupedData = [];
let groupedItem = [];
originalData.forEach((data, index) => {
groupedItem.push(data);
if (index % 4 === 3) {
groupedData.push(groupedItem);
groupedItem = [];
}
});
console.log(groupedData);
I have the following code snippet, where I want original array (filters) to be filtered and get unique filters array.
I think I tried all the methods possible and it (uniqueFilters array) is still same 11 member original array.
Whats wrong?
How can I ensure that this array is actually filtered down to just a few unique elements in it? (they all are coming from the same place and are the same)
UPDATE:
- the answer successfully resolved the issue in js code.
- in the actual app I had to also deal with typescript to use the suggested answer. So maybe will help someone:
let newUniqueFilters = Array.from(new Map(filters.map(f => [f._id, f] as [string, any])).values());
var filters = [{
"_id": "filter1",
"filterIndex": 1,
"filterLabel": "Blur",
"filterURL": "url(#filter1)",
"filterEffects": [{
"name": "feGaussianBlur",
"attributes": [{
"name": "stdDeviation",
"value": 5
}]
}]
}, {
"_id": "filter2",
"filterIndex": 2,
"filterLabel": "Shadow",
"filterURL": "url(#filter2)",
"filterEffects": [{
"name": "feOffset",
"attributes": [{
"name": "dx",
"value": 20
}, {
"name": "dy",
"value": 20
}, {
"name": "result",
"value": "offOut"
}, {
"name": "in",
"value": "SourceAlpha"
}]
}, {
"name": "feGaussianBlur",
"attributes": [{
"name": "stdDeviation",
"value": 7
}, {
"name": "in",
"value": "offOut"
}, {
"name": "result",
"value": "blurOut"
}]
}, {
"name": "feBlend",
"attributes": [{
"name": "mode",
"value": "normal"
}, {
"name": "in2",
"value": "blurOut"
}, {
"name": "in",
"value": "SourceGraphic"
}]
}]
}, {
"_id": "filter2",
"filterIndex": 2,
"filterLabel": "Shadow",
"filterURL": "url(#filter2)",
"filterEffects": [{
"name": "feOffset",
"attributes": [{
"name": "dx",
"value": 20
}, {
"name": "dy",
"value": 20
}, {
"name": "result",
"value": "offOut"
}, {
"name": "in",
"value": "SourceAlpha"
}]
}, {
"name": "feGaussianBlur",
"attributes": [{
"name": "stdDeviation",
"value": 7
}, {
"name": "in",
"value": "offOut"
}, {
"name": "result",
"value": "blurOut"
}]
}, {
"name": "feBlend",
"attributes": [{
"name": "mode",
"value": "normal"
}, {
"name": "in2",
"value": "blurOut"
}, {
"name": "in",
"value": "SourceGraphic"
}]
}]
}, {
"_id": "filter1",
"filterIndex": 1,
"filterLabel": "Blur",
"filterURL": "url(#filter1)",
"filterEffects": [{
"name": "feGaussianBlur",
"attributes": [{
"name": "stdDeviation",
"value": 5
}]
}]
}, {
"_id": "filter1",
"filterIndex": 1,
"filterLabel": "Blur",
"filterURL": "url(#filter1)",
"filterEffects": [{
"name": "feGaussianBlur",
"attributes": [{
"name": "stdDeviation",
"value": 5
}]
}]
}, {
"_id": "filter1",
"filterIndex": 1,
"filterLabel": "Blur",
"filterURL": "url(#filter1)",
"filterEffects": [{
"name": "feGaussianBlur",
"attributes": [{
"name": "stdDeviation",
"value": 5
}]
}]
}, {
"_id": "filter2",
"filterIndex": 2,
"filterLabel": "Shadow",
"filterURL": "url(#filter2)",
"filterEffects": [{
"name": "feOffset",
"attributes": [{
"name": "dx",
"value": 20
}, {
"name": "dy",
"value": 20
}, {
"name": "result",
"value": "offOut"
}, {
"name": "in",
"value": "SourceAlpha"
}]
}, {
"name": "feGaussianBlur",
"attributes": [{
"name": "stdDeviation",
"value": 7
}, {
"name": "in",
"value": "offOut"
}, {
"name": "result",
"value": "blurOut"
}]
}, {
"name": "feBlend",
"attributes": [{
"name": "mode",
"value": "normal"
}, {
"name": "in2",
"value": "blurOut"
}, {
"name": "in",
"value": "SourceGraphic"
}]
}]
}, {
"_id": "filter1",
"filterIndex": 1,
"filterLabel": "Blur",
"filterURL": "url(#filter1)",
"filterEffects": [{
"name": "feGaussianBlur",
"attributes": [{
"name": "stdDeviation",
"value": 5
}]
}]
}, {
"_id": "filter2",
"filterIndex": 2,
"filterLabel": "Shadow",
"filterURL": "url(#filter2)",
"filterEffects": [{
"name": "feOffset",
"attributes": [{
"name": "dx",
"value": 20
}, {
"name": "dy",
"value": 20
}, {
"name": "result",
"value": "offOut"
}, {
"name": "in",
"value": "SourceAlpha"
}]
}, {
"name": "feGaussianBlur",
"attributes": [{
"name": "stdDeviation",
"value": 7
}, {
"name": "in",
"value": "offOut"
}, {
"name": "result",
"value": "blurOut"
}]
}, {
"name": "feBlend",
"attributes": [{
"name": "mode",
"value": "normal"
}, {
"name": "in2",
"value": "blurOut"
}, {
"name": "in",
"value": "SourceGraphic"
}]
}]
}, {
"_id": "filter1",
"filterIndex": 1,
"filterLabel": "Blur",
"filterURL": "url(#filter1)",
"filterEffects": [{
"name": "feGaussianBlur",
"attributes": [{
"name": "stdDeviation",
"value": 5
}]
}]
}, {
"_id": "filter2",
"filterIndex": 2,
"filterLabel": "Shadow",
"filterURL": "url(#filter2)",
"filterEffects": [{
"name": "feOffset",
"attributes": [{
"name": "dx",
"value": 20
}, {
"name": "dy",
"value": 20
}, {
"name": "result",
"value": "offOut"
}, {
"name": "in",
"value": "SourceAlpha"
}]
}, {
"name": "feGaussianBlur",
"attributes": [{
"name": "stdDeviation",
"value": 7
}, {
"name": "in",
"value": "offOut"
}, {
"name": "result",
"value": "blurOut"
}]
}, {
"name": "feBlend",
"attributes": [{
"name": "mode",
"value": "normal"
}, {
"name": "in2",
"value": "blurOut"
}, {
"name": "in",
"value": "SourceGraphic"
}]
}]
}]
// first method:
var uniqueFilters = [];
for(let i = 0; i < filters.length; i++) {
if(uniqueFilters.indexOf(filters[i]) == -1){
uniqueFilters.push(filters[i])
}
}
console.log("first method")
console.log("original array length:" + filters.length)
console.log("unique array length:" + uniqueFilters.length)
// second method:
//var uniqueFilters = filters.filter(function(elem, index, self) {
// return index == self.indexOf(elem);
//});
//console.log("second method")
//console.log("original array length:" + filters.length)
//console.log("unique array length:" + uniqueFilters.length)
// suggested method 1:
var newUniqueFilters = Array.from(new Map(filters.map(f => [f._id, f])).values());
console.log(newUniqueFilters)
You can use a Map:
filters = Array.from(new Map(filters.map(f => [f._id, f])).values());
This assumes that it is enough to compare the _id values, which uniquely identify filters.
Note that comparing objects themselves (with indexOf or similar methods) will never show duplicates, as all the objects are different references (copies), even though they look the same. In general {} === {} is always false.
It's not working because every element in filter array has different memory location and object are compared by the memory location.
So every time you compare that object exist of filter array in uniqueFilters, it simply doesn't exist because every object has different memory location.
so it will push every element in uniqueFilters.
Try changing this line
if(uniqueFilters.indexOf(filters[i]) == -1){
to
if(uniqueFilters.indexOf(filters[i]) === -1){
If not worikingn you can too try comparing a specific attibute to all uniqueFilter
I have two variables array1 and array2 as following and I want to put the values of array2 into array1 for the properties present in array1 and rest of the properties should remain the same with default values.
One solution I have is to iterate through the array length and set values for found properties and but my array is too long to perform iteration (the array supplied in this question is just a raw value).
I need some better way other than iteration.
var array1=[
{
"name": "a",
"value": 0,
"level": [
{
"name": "a1",
"value": 0
},
{
"name": "a2",
"value": 0
}
]
},
{
"name": "b",
"value": 0,
"level": [
{
"name": "b1",
"value": 0
},
{
"name": "b2",
"value": 0
}
]
},
{
"name": "c",
"value": 0,
"level": [
{
"name": "c1",
"value": 0
},
{
"name": "c2",
"value": 0
}
]
}
]
var array2=[
{
"name": "a",
"value": 1,
"level": [
{
"name": "a1",
"value": 1
},
{
"name": "a2",
"value": 0
}
]
},
{
"name": "b",
"value": 1,
"level": [
{
"name": "b1",
"value": 0
},
{
"name": "b2",
"value": 1
}
]
}
]
and the required output is
var final_array=[
{
"name": "a",
"value": 1,
"level": [
{
"name": "a1",
"value": 1
},
{
"name": "a2",
"value": 0
}
]
},
{
"name": "b",
"value": 1,
"level": [
{
"name": "b1",
"value": 0
},
{
"name": "b2",
"value": 1
}
]
},
{
"name": "c",
"value": 0,
"level": [
{
"name": "c1",
"value": 0
},
{
"name": "c2",
"value": 0
}
]
}
]
A recursive solution with two iterators, one for arrays iterateA and one for objects iterateO. This proposal uses the thisArg for reference to json2.
Basically both callbacks iterates over the items or keys and checks if this is set and if the actual item is present in this. if not, the function returns.
The rest is straight forward, if an object is found, then it iterates over the keys and the object, if an array is found, the it it iterates over the array.
Only in the case of k === 'value' the value of this[k] is to o[k] assigned.
var json1 = [{ "name": "a", "value": 0, "level": [{ "name": "a1", "value": 0 }, { "name": "a2", "value": 0 }] }, { "name": "b", "value": 0, "level": [{ "name": "b1", "value": 0 }, { "name": "b2", "value": 0 }] }, { "name": "c", "value": 0, "level": [{ "name": "c1", "value": 0 }, { "name": "c2", "value": 0 }] }],
json2 = [{ "name": "a", "value": 1, "level": [{ "name": "a1", "value": 1 }, { "name": "a2", "value": 0 }] }, { "name": "b", "value": 1, "level": [{ "name": "b1", "value": 0 }, { "name": "b2", "value": 1 }] }];
function iterateO(o) {
return function (k) {
if (!this || !(k in this)) {
return;
}
if (typeof o[k] === 'object') {
Object.keys(o[k]).forEach(iterateO(o[k]), this[k]);
return;
}
if (Array.isArray(o[k])) {
o[k].forEach(iterateA, this[k]);
return;
}
if (k === 'value') {
o[k] = this[k];
}
};
}
function iterateA(a, i, aa) {
if (!this || !(i in this)) {
return;
}
if (typeof a === 'object') {
Object.keys(a).forEach(iterateO(a), this[i]);
return;
}
if (Array.isArray(a)) {
a.forEach(iterateA, this[i]);
return;
}
}
json1.forEach(iterateA, json2);
document.write('<pre>' + JSON.stringify(json1, 0, 4) + '</pre>');