Converting the one form of JSON Array Data to another? - javascript

I'm new to software Field. i have a json array of objects like
var treeObj = [
{
"name": "sriram",
"refernce_id": "SAN001",
"sponer_id": "SAN000"
},
{
"name": "neeraja",
"refernce_id": "SAN002",
"sponer_id": "SAN001"
},
{
"name": "upender",
"refernce_id": "SAN003",
"sponer_id": "SAN001"
},
{
"name": "manoj",
"refernce_id": "SAN004",
"sponer_id": "SAN002"
},
{
"name": "shirisha",
"refernce_id": "SAN005",
"sponer_id": "SAN002"
},
{
"name": "ragu",
"refernce_id": "SAN006",
"sponer_id": "SAN003"
},
{
"name": "santhu",
"refernce_id": "SAN007",
"sponer_id": "SAN003"
}
];
Here i will pass the above object to a function. in that function i need to compare reference id with sponer_id in every object and if they are equal we need to push them into an Array which we call as child object just like below and again we need to check in the child Array that the reference id in is present in sponer_id of above object if it is present again we need to push them to child array into object which contains the reference_id. the final array Object looks like.
[
{
"name": "sriram",
"parent": null,
"children": [
{
"name": "neeraja",
"parent": "sriram",
"children": [
{
"name": "manoj",
"parent": "neeraja"
},
{
"name": "shirisha",
"parent": "neeraja"
}
]
},
{
"name": "upender",
"parent": "sriram",
"children": [
{
"name": "ragu",
"parent": "neeraja"
},
{
"name": "santhu",
"parent": "neeraja"
}
]
}
]
}
]
Here sriram's reference id of treeObj is present as sponer id in neeraja and upender object. so neeraja and upender becomes child to sriram. and neeraja's reference_id is present as sponer_id in manoj and shirisha objects of treeObj. simultaneously the child can many more child objects and we need to format the object dynamically.
The function which i wrote looks like
var mainArr = [], subArrs = [], subObj={}, subIds = [], find = "SAN001";
formatData(treeObj);
function formatData(treeObj){debugger;
var arr = [];
for(var x=0; x<= treeObj.length-1; x++){debugger;
var sampData = treeObj[x];
if(find == sampData.sponer_id){
arr.push(sampData.refernce_id);
subArrs.push(sampData);
}
}
subIds.push(arr);
console.log(subIds);
console.log(subArrs);
formatData(subArrs);
}
please guide me where i went wrong. thanks in advance.

//1. find all items the have no parent and push them on a stack like so:
let stack = treeObj.reduce((list, item) => {
if (<ids match>) list.push(item);
return item;
}, []),
let result = [].concat(stack);
//2. while loop the stack:
while (stack.length > 0) {
let item = stack.shift();
item.children = treeObj.reduce((list, child) => {
if (<ids match>) {
list.push(child);
}
return list;
}, []).map(child => {
child.parent = item;
stack.unshift(item);
return child;
});
}
return result;
UPDATE
So in »good old JS« and with some improvements:
var stack = treeObj.filter(function (item) {
return item.<parent_id> === item.<child_id> });
var result = [].concat(stack);
while (stack.length > 0) {
var item = stack.shift();
item.children = treeObj.filter(function (child) {
return item.<id> === child.<parent_id>;
});
item.children.forEach(function (child) { stack.unshift(child) });
}
Basically:
find the root(s) and save them on the stack
while.length > 0
shift() the first item from the stack
find all children of that item and unshift them on the stack
Done
Adding a parent property to the items, or removing unneeded one, can be done in the loop. The whole thing can also be done using recursion, but I once ran in the »too much recursion error« by doing such stuff, so I prefer an iterative approach. And of course, instead of .reduce, .filter and .forEach, you can use regular loops, but I prefer a functional style. All in all, no matter how you do it, it is not that difficult, just find the elements to start with and then repeat with all of their children and so on. Withing the while loop all children are found, or, the whole subtree with that element as root.
Good luck!

You're basically trying to convert an array to a n-ary tree.
Entering your original tree function into formatData gives you an array (arr) with the referenceIDs of all objects having SAN001 as parent and another array (subArrs) with all children of with sponerId SAN001.
You then store the arr in subIds, log subIds and subArr and proceed to call format data on subArrs recursively. Then you check on subArr which objects have "SAN001 as predecessor" (which should be all objects at that time) and push that object in subArr. If im not getting it wrong this leads to an infinite loop.
Starting points for improvements:
you're "find" variable does not change, it's hardwired to "SAN001" - this would maybe be okay for your first trip when you're 100% sure that the root object has always this referenceID. But in the second trip, you want to check which objects depend on a second level element, so you need to set find to an corresponding referenceId.
Your subArrs contains all objects depending on SAN001. But in the second and following trips, you don't want to get childrens of SAN001 but child of objects in the subArr. So you need to travers old objects finding children of objects in subArr instead of traversing subArr seeking children of SAN001.
Hope that clear's it up a little bit.
A hint for further research: You're basically trying to "convert an array into a n-ary tree" with javascript.

Related

how to iterate parent to child objects and pushed into an array javascript (vuejs)

I have json data like this.
var obj= {
"id": "6",
"name": "parent",
"path": "/",
"category": "folder",
"fid":"6"
"children": [
{
//some values
},
{
//some other values
}
]
}
how to iterate and push it into an new array.
type declaration
getEntry: Array<Object> = []
pushing into an array method
get addedEntry() {
let files = []
this.getEntry = files.push(this.obj)
}
But, i am getting type error. How to push this object into an array or make it array.?
The push method returns a Number representing the new value of the array. That's why you are getting a TypeError (you are assigning a Number to an Array of Objects).
You should do the following instead.
get addedEntry() {
let files = []
files.push(this.obj)
this.getEntry = files
}
Here's the docs entry for the push method in JavaScript.

remove object from array if property value match

I have array of objects that look like:
{
"brandid": id,
"brand": string,
"id": id,
"categoryId": id,
"category": string,
"factory": string,
"series": string,
"status": 0,
"subStatus": 1
}
if the series property value matches another series property value in the other objects in the array, that object needs to be removed from the array.
Currently I have attempted to push them to a duplicate Array with :
const seriesResCopy = seriesRes;
const dupArray = []
for (const thing of seriesResCopy) {
for (const item of seriesRes) {
if (thing.series === item.series) {
dupArray.push(item);
}
}
}
but this does not work. From examples I have seem my issue has been that I do not have a definite list of duplicate values to look for.
Any help would be much appreciated.
You could use a Set of series to filter out duplicates:
const exists = new Set();
seriesRes = seriesRes.filter(({series}) => !exists.has(series) && exists.add(series));
This uses: Array.prototype.filter, Object destructuring and some logical tricks.
The same can be done by mutating the array:
const exists = new Set();
for(const [index, {series}] of seriesRes.entries()) {
if(!exists.has(series) {
exists.add(series);
} else {
seriesRes.splice(index, 1);
}
}
To filter duplicates from the array and keep the first instance:
let seriesWithoutDuplicates = seriesRes.filter((s, i, self) => {
return self.findIndex(z => z.series === s.series) === i;
});

How can I remove null from JSON object with AngularJS?

I'm trying to remove an object from Json Object it works..but it replace it with null..i dont know why, how can i remove the null value from the json..heres the function :
company.deleteExternalLinkFromGrid = function (row, matricule) {
// console.log('Inside of deleteModal, code = ' + code);
//$scope.sitting= {};
console.log(matricule);
//console.log(JSON.stringify(linkJsonObj));
delete linkJsonObj[matricule];
console.log(JSON.stringify(linkJsonObj));
};
heres the object:
[{"name":"xxx","link":"www.ddd.com","id":0,"$$hashKey":"uiGrid-001Z"},null,null]
You can use filter(), x will be without null's.
function test()
{
var x =[{"name":"xxx","link":"www.ddd.com","id":0,"$$hashKey":"uiGrid-001Z"},null,null].filter(isNotNull);
alert(JSON.stringify(x));
}
function isNotNull(value) {
return value != null;
}
fiddle
There are multiple ways to delete an object from an array of objects in JavaScript. You don't need AngularJS for that, you can use VanillaJS.
If you just want the nulls filtered you can use
var yourArray =[{"name":"xxx","link":"www.ddd.com","id":0,"$$hashKey":"uiGrid-001Z"},null,null];
yourArray = yourArray.filter(function(elt){
return elt != null;
});
But this loses the original reference to your object.
If you want to keep the reference, Use array.splice().
yourArray.forEach(function(){
yourArray.splice(yourArray.indexOf(null),1);
});
now you will have null less array in yourArray. This actually deletes an object from an array without changing the reference,
delete will replaced the object with undefined
You can filter the array to remove them using Array#filter()
var array = [{
"name": "xxx",
"link": "www.ddd.com",
"id": 0,
"$$hashKey": "uiGid-001Z"
}, {
"name": "xx",
"link": "www.dddcom",
"id": 1,
"$$hashey": "uiGrid-0029"
}, {
"name": "xxx",
"link": "www.ddd.com",
"id": 2
}];
delete array[1];
array = array.filter(a=>a);
console.log(JSON.stringify(array));

Moving values up in nested hierarchy until key is no longer named '_ignore'

Given an object as shown below, how would I approach moving all values up in the hierarchy until their parent no longer is named _ignore?
In an attempt to transform Excel CSV data to a nested object, I ended up with something that looks like the following:
// Old structure:
var obj = {
_root: {},
_top1: {
"_ignore": {
"_ignore": [
"I can no longer traverse down",
"so the list that contains this",
"text should be placed under the",
"_top1 node, which is the first",
"parent not named _ignore. It should",
"be the only child to '_top1'."
]
}
},
_top2: {}
}
_root and _top2 should not be touched, but the top1 should have the lowest-level list as its value in the final structure. I'd like the object to look like this:
// Desired structure:
var obj = {
_root: {},
_top1: [
"I can no longer traverse down",
"so the list that contains this",
"text should be placed under the",
"_top1 node, which is the first",
"parent not named _ignore"
],
_top2: {}
}
I know I'm in the recursive domain, just haven't been able to apply it in a proper manner.
Help/direction is greatly appreciated.
Indeed you basically just want the contents of the deepest _ignore. Since you're also converting all ancestor objects (except for obj itself) to arrays, it's safe to say that any other properties can be destroyed. In other words, an object has either an _ignore property or is the actual content we're looking for.
In one sentence you could say; give me the contents of _ignore if is there, and recurse that.
In pseudo code:
function findContents (level) {
if (i have an ignored level)
return findContents (ignored level)
else
return level
}
In Javascript code:
const findContents = obj => obj._ignore
? findContents(obj._ignore)
: obj;
And to apply that to your structure:
obj._top1 = findContents(obj._top1);
Have fun
Maybe this function can help you:
const removeIgnore = (obj) => {
let newObj = Object.assign({}, obj);
const findStructure = (obj) => {
const keys = Object.keys(obj)
if (keys.length == 0) return obj
return (keys[0] === '_ignore') ? findStructure(obj[keys[0]]) : obj
}
for (k in newObj) newObj[k] = findStructure(newObj[k])
return newObj
}
It will iterate over all root keys, and search for the deepest structure that is not part of a _ignore key. Will return a new object with the modified data.
Demo:
/* 3 deeps _ignore */
var obj = {
_root: {},
_top1: {
"_ignore": {
"_ignore": {
"_ignore": [
"I can no longer traverse down",
"so the list that contains this",
"text should be placed under the",
"_top1 node, which is the first",
"parent not named _ignore. It should",
"be the only child to '_top1'."
]
}
}
},
_top2: {}
}
const newObj = removeIgnore(obj);
console.log(newObj);
/*
{ _root: {},
_top1:
[ 'I can no longer traverse down',
'so the list that contains this',
'text should be placed under the',
'_top1 node, which is the first',
'parent not named _ignore. It should',
'be the only child to \'_top1\'.' ],
_top2: {} }
*/
You will need to do a depth first search down the tree to replace the ignores
var obj = {
_root: {},
_top1: {
"_ignore": {
"_ignore": [
"I can no longer traverse down",
"so the list that contains this",
"text should be placed under the",
"_top1 node, which is the first",
"parent not named _ignore. It should",
"be the only child to '_top1'."
]
}
},
_top2: {}
}
function hoistIgnore(item, parent, parent_key){
if(Array.isArray(item) || !(typeof item === "object")) {
parent[parent_key] = item;
return item
}
for(var key in item){
if(key === "_ignore"){
hoistIgnore(item[key], parent, parent_key);
} else {
hoistIgnore(item[key], item, key);
}
}
return item
}
console.log(hoistIgnore(obj))

Underscore recursive groupBy array of string arrays

I'm trying to combine and group an array with a bunch of flat arrays that contain only strings, no objects.
So my array looks something like this:
var array = [
["MotherNode", "Node1", "ChildNode1", "ChildOfChildNode1"],
["MotherNode", "Node1", "ChildNode2", "ChildOfChildNode2"],
["MotherNode", "Node2", "ChildNode3", "ChildOfChildNode3"],
["MotherNode", "Node2", "ChildNode3", "ChildOfChildNode4"],
["MotherNode", "Node3", "ChildNode4", "ChildOfChildNode5"],
["MotherNode", "Node3", "ChildNode4", "ChildOfChildNode5"]
]
Im doing this in javascript/angularjs and so far I've gathered that the best solution is probably to use underscore.js groupBy/combine methods. However most of the examples that i can find are dealing with arrays of objects where they can group them together by using a value's key. And I'm not good enough with algorithms yet to be able to figure this out on my own.
The array I'm dealing with can have hundreds of values and the result array could get 5-10 levels deep.
The result I'd like by parsing the above array would look something like this:
var result= {
"MotherNode": [{
"Node1":[{
"ChildNode1":"ChildOfChildNode1"
},{
"ChildNode2":"ChildOfChildNode2"
},{
"Node2":[{
"ChildNode3":["ChildOfChildNode3","ChildOfChildNode4"]
},{
"Node3":[{
"ChildNode4":"ChildOfChildNode5"
}
]
}
So does anyone have any clue how this can be done? I'm completely out of ideas.
I solved this using _.reduce grouping wasnt the way to go
var result = _.reduce(array,function(memo, val){
var tmp = memo;
_.each(val, function(fldr){
if(!_.has(tmp, fldr)){
tmp[fldr] = {}
}
tmp = tmp[fldr]
})
return memo
},{})
the end leaf wont be set as a value but it should be easy to change that behavior to whatever suits you use case
{ MotherNode:
{ Node1:
{ ChildNode1: { ChildOfChildNode1: {} },
ChildNode2: { ChildOfChildNode2: {} } },
Node2: { ChildNode3: { ChildOfChildNode3: {}, ChildOfChildNode4: {} } },
Node3: { ChildNode4: { ChildOfChildNode5: {} } } } }

Categories