Related
My array look like this:
var theset=[
{
"set": "1",
"data": [
{ "field": "A", "value": "111", "check": true },
{ "field": "B", "value": "111", "check": false },
{ "field": "C", "value": "111", "check": true }
]
},
{
"set": "2",
"data": [
{ "field": "A", "value": "111", "check": true },
{ "field": "B", "value": "222", "check": false },
{ "field": "C", "value": "222", "check": true }
]
},
{
"set": "3",
"data": [
{ "field": "A", "value": "333", "check": true },
{ "field": "B", "value": "333", "check": false },
{ "field": "C", "value": "222", "check": true }
]
},
{
"set": "4",
"data": [
{ "field": "A", "value": "444", "check": true },
{ "field": "B", "value": "333", "check": false },
{ "field": "C", "value": "444", "check": true }
]
}
];
What I want to do is validate the "value" with other set on the same field only when the "check" is true.
The result is to return a true if there is a duplication of "value" in the set. The example will return a true because
set 1: having duplicate value for field A with set 2
set 2: having duplicate value for field A with set 1, duplicate value for field C with set 3
set 3: having duplicate value for field C with set 2
set 4: not consider as duplicate, even though the value of field B match with set 3 because of the check is false
so far I tried to do for loop on the list but this will have a lot of nested loop which is not efficient.
for(var i=0; i<theset.length; i++){
var checking = theset[i].data;
for(var j=0; j<checking.length; j++){
if(checking[j].check){
for(var k=0; k<theset.length; k++){
if(k!=i){
var checking2 = theset[k].data;
for(var l=0; l<checking2.length; l++){
...
}
}
}
}
}
}
Can anybody help me?
one way can be for each set to filter the duplicate data with array.filter
then if there is duplicate do the wanted treatment
var theset = [
{
"set": "1",
"data": [
{ "field": "A", "value": "111", "check": true },
{ "field": "B", "value": "111", "check": false },
{ "field": "C", "value": "111", "check": true }
]
},
{
"set": "2",
"data": [
{ "field": "A", "value": "111", "check": true },
{ "field": "B", "value": "222", "check": false },
{ "field": "C", "value": "222", "check": true }
]
},
{
"set": "3",
"data": [
{ "field": "A", "value": "333", "check": true },
{ "field": "B", "value": "333", "check": false },
{ "field": "C", "value": "222", "check": true }
]
},
{
"set": "4",
"data": [
{ "field": "A", "value": "444", "check": true },
{ "field": "B", "value": "333", "check": false },
{ "field": "C", "value": "444", "check": true }
]
}
];
theset.forEach(set => {
var duplicate = set.data.filter(data => {
return theset.some(oneSet => oneSet.data.some(oneData => oneData.value === data.value));
});
if (duplicate.length) {
console.log(`the following set have duplicate ${set.set}`);
console.log(duplicate);
//treat as you want the set and the duplicate
}
});
i would do it with a hash map
const theset = [
{
"set": "1",
"data": [
{ "field": "A", "value": "111", "check": true },
{ "field": "B", "value": "111", "check": false },
{ "field": "C", "value": "111", "check": true }
]
},
{
"set": "2",
"data": [
{ "field": "A", "value": "111", "check": true },
{ "field": "B", "value": "222", "check": false },
{ "field": "C", "value": "222", "check": true }
]
},
{
"set": "3",
"data": [
{ "field": "A", "value": "333", "check": true },
{ "field": "B", "value": "333", "check": false },
{ "field": "C", "value": "222", "check": true }
]
},
{
"set": "4",
"data": [
{ "field": "A", "value": "444", "check": true },
{ "field": "B", "value": "333", "check": false },
{ "field": "C", "value": "444", "check": true }
]
}
];
const hashmap = {};
theset.forEach((item) => {
item.data.forEach((obj) => {
if (!obj.check) {
return;
}
const key = JSON.stringify(obj);
if (!hashmap[key]) {
hashmap[key] = [];
}
hashmap[key].push(item.set);
})
})
console.log('hashmap', hashmap)
as a result you would get the following output:
{
"obj1": ["1","2"],
"obj2": ["1"],
"obj3": ["2","3"],
"obj4": ["3"],
"obj5": ["4"],
"obj6": ["4"]
}
obj1 is common for set 1 and set 2
obj3 is common for set 2 and set 3
you have the all needed information for your conclusions
of course, you could use a custom hash function rather than JSON.stringify()
I have a this type of a json object.
{
"id": "001",
"type": "A",
"value": "aaaaa",
"data:": {},
"path": ["001"],
"children": [
{
"id": "002",
"type": "A",
"value": "aaaaa",
"data:": {},
"path": ["001", "002"],
"children": []
},
{
"id": "003",
"type": "A",
"value": "aaaaa",
"data:": {},
"path": ["001", "003"],
"children": [
{
"id": "00001",
"type": "B",
"children": []
}
]
},
{
"id": "004",
"type": "A",
"value": "aaaaa",
"data:": {},
"path": ["001", "004"],
"children": [
{
"id": "005",
"type": "A",
"value": "aaaaa",
"data:": {},
"path": ["001", "004", "005"],
"children": []
},{
"id": "005",
"type": "A",
"value": "aaaaa",
"data:": {},
"path": ["001", "004", "005"],
"children": [
{
"id": "00002",
"type": "B",
"children": []
}
]
}
]
},
{
"id": "00003",
"type": "B",
"children": []
}
]
}
I need to replace all the object which is type: "B" , with this (which is mentioned below) type of object which I can get from an object with ids as keys of typed B. This typed B objects can be nested anywhere either as a first child or fifth child of a nested arrays of children
{
"id": "002",
"type": "A",
"value": "aaaaa",
"data:": {},
"children": []
},
How can I do that? This can be deeply nested and there's no specific place where we should replace the objects, beforehand. So, I need to go through the entire object and do that. How should I get it done?
EDIT
I updated the code in the question slightly. There's a path property of the nested in each object, except for typed B objects. So, when replacing the typed B properties with the other object, I need to add the paths in there as well.
eg: path for id: "00001", typed B object should be : ["001", "003", "00001"]
EDIT :
Expected result
{
"id": "001",
"type": "A",
"value": "aaaaa",
"data:": {},
"path": ["001"],
"children": [
{
"id": "002",
"type": "A",
"value": "aaaaa",
"data:": {},
"path": ["001", "002"],
"children": []
},
{
"id": "003",
"type": "A",
"value": "aaaaa",
"data:": {},
"path": ["001", "003"],
"children": [
{
"id": "002",
"type": "A",
"value": "aaaaa",
"data:": {},
"path": ["001", "003", "002"],
"children": []
},
]
},
{
"id": "004",
"type": "A",
"value": "aaaaa",
"data:": {},
"path": ["001", "004"],
"children": [
{
"id": "005",
"type": "A",
"value": "aaaaa",
"data:": {},
"path": ["001", "004", "005"],
"children": []
},{
"id": "005",
"type": "A",
"value": "aaaaa",
"data:": {},
"path": ["001", "004", "005"],
"children": [
{
"id": "002",
"type": "A",
"value": "aaaaa",
"data:": {},
"path": ["001", "004", "005", "002"],
"children": []
}
]
}
]
},
{
"id": "002",
"type": "A",
"value": "aaaaa",
"data:": {},
"path": ["001", "002"],
"children": []
}
]
}
lodash if you don't mind.
Use cloneDeepWith to clone the entire tree and replace a specific value.
const data = {"id":"001","type":"A","value":"aaaaa","data:":{},"children":[{"id":"002","type":"A","value":"aaaaa","data:":{},"children":[]},{"id":"003","type":"A","value":"aaaaa","data:":{},"children":[{"id":"00001","type":"B","children":[]}]},{"id":"004","type":"A","value":"aaaaa","data:":{},"children":[{"id":"005","type":"A","value":"aaaaa","data:":{},"children":[]},{"id":"005","type":"A","value":"aaaaa","data:":{},"children":[{"id":"00002","type":"B","children":[]}]}]},{"id":"00003","type":"B","children":[]}]};
const result = _.cloneDeepWith(data, (value) => {
const newObj = {"id": "002", "type": "A", "value": "---NEW VALUE FOR 'B' TYPE---", "data:": {} };
return (value.type === 'B') ? { ...value, ...newObj} : _.noop();
});
console.dir(result, { depth: null } );
.as-console-wrapper{min-height: 100%!important; top: 0}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.js" integrity="sha512-2iwCHjuj+PmdCyvb88rMOch0UcKQxVHi/gsAml1fN3eg82IDaO/cdzzeXX4iF2VzIIes7pODE1/G0ts3QBwslA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
--- Update 2--- (Without lodash)
Use local variable to store and combine current path.
const data = { "id": "001", "type": "A", "value": "aaaaa", "data:": {}, "path": ["001"], "children": [{ "id": "002", "type": "A", "value": "aaaaa", "data:": {}, "path": ["001", "002"], "children": [] }, { "id": "003", "type": "A", "value": "aaaaa", "data:": {}, "path": ["001", "003"], "children": [{ "id": "00001", "type": "B", "children": [] }] }, { "id": "004", "type": "A", "value": "aaaaa", "data:": {}, "path": ["001", "004"], "children": [{ "id": "005", "type": "A", "value": "aaaaa", "data:": {}, "path": ["001", "004", "005"], "children": [] }, { "id": "005", "type": "A", "value": "aaaaa", "data:": {}, "path": ["001", "004", "005"], "children": [{ "id": "00002", "type": "B", "children": [] }] }] }, { "id": "00003", "type": "B", "children": [] }] }
const deepReplace = (obj, prevPath = []) => {
if (obj.type === 'A') {
if (obj.children.length) {
obj.children = obj.children.map((childObj) => deepReplace(childObj, obj.path))
}
return obj;
};
if (obj.type === 'B') {
const id = '002';
return { id, type: "A", value: "aaaaa", path: [...prevPath, id], data: {}, children: []};
};
};
console.dir(deepReplace(data), { depth: null });
.as-console-wrapper{min-height: 100%!important; top: 0}
This looks like a tree traversal problem. Here's a way to handle that with depth-first search without recursion.
As mentioned in this answer, recursion should be avoided whenever possible, as it requires more memory and is more difficult to debug than an iterative implementation.
Updated per adjustment in question
const data = {"id":"001","type":"A","value":"aaaaa","data:":{},"path":["001"],"children":[{"id":"002","type":"A","value":"aaaaa","data:":{},"path":["001","002"],"children":[]},{"id":"003","type":"A","value":"aaaaa","data:":{},"path":["001","003"],"children":[{"id":"00001","type":"B","children":[]}]},{"id":"004","type":"A","value":"aaaaa","data:":{},"path":["001","004"],"children":[{"id":"005","type":"A","value":"aaaaa","data:":{},"path":["001","004","005"],"children":[]},{"id":"005","type":"A","value":"aaaaa","data:":{},"path":["001","004","005"],"children":[{"id":"00002","type":"B","children":[]}]}]},{"id":"00003","type":"B","children":[]}]};
const dfs = () => {
const stack = [[data, null]];
while(stack.length) {
const [curr, parent] = stack.pop();
// check for match on type
if (curr.type === "B") {
curr.type = "A";
curr.id = "002";
curr.value = "aaaaa";
curr.data = {};
curr.path = [...parent?.path.slice() ?? [], "002"];
}
curr.children.forEach(child => stack.push([child, curr]));
}
};
dfs();
const output = document.getElementById("output");
output.innerText = JSON.stringify(data, null, 2);
<pre id="output" />
I played around with this in the console and it did what you wanted (based on the json array provided, setting all the "B" to "A" types). It's a recursive function so on any nested child it meets in the "children" array it would call the function again on each item in the array.
function fixObjects (obj) {
if (obj["type"] === "B") {
obj["type"] = "A";
obj["id"] = "002";
obj["value"] = "aaaaa";
obj["data"] = {};
}
if (obj["children"].length > 0) {
obj["children"].forEach (child => fixObjects (child));
}
}
fixObjects (_yourArray)
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 object with key values, and those keys each contain an array of objects:
var obj = {
"0": [
{
"category": "A",
"index": 0,
"property": "Name",
"value": "Bob"
},
{
"category": "A",
"index": 0,
"property": "Surname",
"value": "Dylan"
}
],
"1": [
{
"category": "A",
"index": 1,
"property": "Name",
"value": "Elvis"
},
{
"category": "A",
"index": 1,
"property": "Surname",
"value": "Presley"
}
]
}
How would I go about merging the objects into one single array with the objects combined therein? The objective is to have the result return the following:
var obj2 = [
{
"category": "A",
"index": 0,
"property": "Name",
"value": "Bob"
},
{
"category": "A",
"index": 0,
"property": "Surname",
"value": "Dylan"
},
{
"category": "A",
"index": 1,
"property": "Name",
"value": "Elvis"
},
{
"category": "A",
"index": 1,
"property": "Surname",
"value": "Presley"
}
]
I've tried to make use of LoDash union and join, however to no avail.
Assuming your example was wrong, and it's actually like below (since what you put in isn't even valid), you can just use Object.values(obj).flat()
var obj = {
"0": [{
"category": "A",
"index": 0,
"property": "Name",
"value": "Bob"
}],
"1": [{
"category": "A",
"index": 1,
"property": "Name",
"value": "Jessica"
}]
}
console.log(Object.values(obj).flat())
I need to rename "text" attribute with "name" in all of objects (parent and child)
the API return the objects as below:
"content": [
[{
"id": 1,
"text": "hierarchy 1",
"icon": "h",
"children": [{
"id": 2,
"text": "hierarchy 11",
"icon": "h",
"children": []
},
{
"id": 3,
"text": "hierarchy 110",
"icon": "h",
"children": []
}
]
}]
]
My API function should return the same result but after rename "text" with "name":
async getTree() {
const res = await axios.get("/api/HierarchyTree");
return res.data.content["0"].map(item => {
return {
...item,
name: item.text
};
});
}
The result should be:
"content": [
{
"id": 1,
"name": "hierarchy 1",
"icon": "h",
"children": [{
"id": 2,
"name": "hierarchy 11",
"icon": "h",
"children": []
},
{
"id": 3,
"name": "hierarchy 110",
"icon": "h",
"children": []
}
]
}
]
Perhaps this?
let content = [
[{
"id": 1,
"text": "hierarchy 1",
"icon": "h",
"children": [{
"id": 2,
"text": "hierarchy 11",
"icon": "h",
"children": []
},
{
"id": 3,
"text": "hierarchy 110",
"icon": "h",
"children": []
}
]
}]
]
content = JSON.parse(JSON.stringify(content[0]).replace(/"text"/g,'"name"'))
console.log(content)