How Can I update an Array based on another Array?
This is how I tried to do:
var ref = [
{
"name": "Jack",
"title": "Manager",
"description": "",
},
{
"name": "Steve",
"title": "CEO",
"description": "A test description",
}
];
var elem = [
{
"name": "Jack",
"title": "Manager",
"description": "",
},
{
"name": "Steve",
"title": "CEO",
"description": "A test description",
}
];
for (var i = 0; i < ref.length; i++) {
ref.indexOf(elem[i]) === -1 ? ref.push(elem[i]) : console.log("This item already exists");
}
console.log(ref);
console.log(elem);
This Loop caused an error because the length is changing after each iterate.
What I want is, to add each element from elem object if it doesn't exist in arr object and of course stays in JOSN format. In my example, it doesn't have to change.
It would be better to run the loop over elem. Also you can't compare objects like that because references will differ, so you will have to do deep check, something like this should work:
var ref = [
{
"name": "Jack",
"title": "Manager",
"description": "",
},
{
"name": "Steve",
"title": "CEO",
"description": "A test description",
}
];
var elem = [
{
"name": "Jack",
"title": "Manager",
"description": "",
},
{
"name": "Steve",
"title": "CEO",
"description": "A test description",
}
];
for (var i = 0; i < elem.length; i++) {
var found = false;
for (var j=0; j<ref.length; j++){
var count = Object.keys(elem[i]).length;
for(var key in elem[i]){
if(ref[j][key] === elem[i][key])
count--;
}
if (count === 0){
found= true;
break;
}
}
if (!found)
ref.push(elem[i]);
}
console.log(ref);
console.log(elem);
To avoid nested loops, you could build a Set with each of the keys that you have in ref. Let's say you consider the name to be the identifying key, then it would look like this:
ref = ref.concat(elem.filter(function (o) {
return !this.has(o.name)
}, new Set(ref.map(o => o.name))));
So, this builds the Set by taking all the names in ref, passes that as this to a filter callback, which checks for each elem entry whether it has a name that is in the set. If so, it is excluded by the filter. This filtered result is concatenated to ref.
If your identifying key is something else, like the combination name and title, then adjust the function that is used in the last map(.......), and apply the same logic in has().
Here is a fiddle (with slightly different sample data) that uses the combination of name and title as identifying key:
var ref = [{
"name": "Jack",
"title": "Manager",
"description": "",
}, {
"name": "Steve",
"title": "CEO",
"description": "A test description",
}];
var elem = [{
"name": "Jack",
"title": "Manager",
"description": "",
}, {
"name": "Steve",
"title": "Programmer",
"description": "Java addict",
}];
ref = ref.concat(elem.filter(function (o) {
return !this.has(JSON.stringify([o.name, o.title]))
}, new Set(ref.map(o => JSON.stringify([o.name, o.title])))));
console.log(ref);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Related
I am working on an angular application. I have an array as follows:
[{
"Name": "Andy"
},
{
"Name": "Bayer"
},
{
"Name": "James"
},
{
"Name": "Doda"
}]
I have another array which containes data as follows:
[
{
"Name": "Andy",
"Id": "1",
"Time": "2020-06-19T11:02+00:00"
},
{
"Name": "Billy",
"Id": "2",
"Time": "2020-06-19T11:05+00:00"
},
{
"Name": "Ciena",
"Id": 5
"Time": "2020-06-19T11:05+00:00"
},
{
"Name": "Doda",
"Id": "4",
"Time": "2020-06-19T11:05+00:00"
}
]
I want a resultant array such that code should check if Name is present in first array, then it should copy data from second array for that Name and push it in resultant array. For example common name between above two array is Andy and Doda, so data from Andy and Doda should be pushed to resultant array as follows:
[{
"Name": "Andy",
"Id": "1",
"Time": "2020-06-19T11:02+00:00"
},
{
"Name": "Bayer"
},
{
"Name": "James"
},
{
"Name": "Doda",
"Id": "4",
"Time": "2020-06-19T11:05+00:00"
}]
At run time I may get many names so code should be generic. I was trying following code which I got over stackoverflow itself
this.newArray = _.map(this.resultantArray, item => {
const value = _.find(this.dataArray, ['Name', item]);
const obj = value ? value : {Name: item};
return obj;
});
But this code is not working as expected as it works fine for the first time but when data comes for second time it appends data to previous data. I want array to be populated again freshly every time I send data. Please help
You can do this with vanilla JS no need for lodash. You can first map it and inside that you can find the value from second array otherwise return the current object:
var arrayTwo = [ { "Name": "Andy", "Id": "1", "Time": "2020-06-19T11:02+00:00" }, { "Name": "Billy", "Id": "2", "Time": "2020-06-19T11:05+00:00" }, { "Name": "Ciena", "Id": "5", "Time": "2020-06-19T11:05+00:00" }, { "Name": "Doda", "Id": "4", "Time": "2020-06-19T11:05+00:00" } ];
var arrayOne = [{ "Name": "Andy"}, { "Name": "Bayer"}, { "Name": "James"}, { "Name": "Doda"}];
var result = arrayOne.map(val=>arrayTwo.find(p=>p.Name==val.Name) || val);
console.log(result);
Suppose first array name is First
First : any [] = [{"Name": "Andy"},{"Name": "Bayer"},{ "Name": "James"},{"Name": "Doda"}]
And Second array name is Second
Second : any[] = [{"Name": "Andy","Id": "1","Time": "2020-06-19T11:02+00:00"},{"Name": "Bayer"},{"Name": "James"},{"Name": "Doda","Id": "4","Time": "2020-06-19T11:05+00:00"}]
Now do looping and check each name of first if its exists in second copy from second and push in result array
result : any[] =[];
this.First.forEach((element) => {
let index = this.Second.findIndex((x) => element.Name== x.Name);
if (index > -1) {
let data = {
this.Second[index].Name,
this.Second[index].Id,
this.Second[index].time,
};
this.result.push(data);
}
}
I have some data which looks like this:
{
"mains": [{
"id": "454",
"name": "main 1",
"subs": [{
"id": "32",
"name": "sub 1"
}, {
"id": "23",
"name": "sub 2"
}, {
"id": "54",
"name": "sub 3"
}],
"image": null
}, {
"id": "654",
"name": "main 2",
"subs": [{
"id": "87",
"name": "sub 1"
}, {
"id": "78",
"name": "sub 2"
}],
"image": null
}]
}
From this I need create 2 lists:
For creating the first list with all the mains …I’ve done this:
mainlist = [];
sublist = [];
for (var i = 0; i < data.mains.length; i++) {
var obj = data.mains[i];
var mnlst = obj.name;
mainlist.push(mnlst);
}
console.log(mainlist);
In this example it will return the names of the mains resulting in 2 names (in this case).
Now what I need to do it to get the names of the subs for each main
So sublist (in this case will return)
“sub 1, sub 2 and sub 3” for main 1 and “sub 1 and sub 2” for main 2 etc…
How can I do this?
You could use another data structure for the sublist with name of main as key.
var data = { "mains": [{ "id": "454", "name": "main 1", "subs": [{ "id": "32", "name": "sub 1" }, { "id": "23", "name": "sub 2" }, { "id": "54", "name": "sub 3" }], "image": null }, { "id": "654", "name": "main 2", "subs": [{ "id": "87", "name": "sub 1" }, { "id": "78", "name": "sub 2" }], "image": null }] },
mainlist = [],
sublist = Object.create(null);
data.mains.forEach(function (main) {
mainlist.push(main.name);
sublist[main.name] = main.subs.map(function (sub) {
return sub.name;
});
})
console.log(mainlist);
console.log(sublist['main 1']);
console.log(sublist);
.as-console-wrapper { max-height: 100% !important; top: 0; }
you actually had the right idea in your question title - nested loops, you need to iterate over the internal subs in each "main" like this:
mainlist = [];
sublist = {};
for (var i = 0; i < data.mains.length; i++) {
var obj = data.mains[i];
var mnlst = obj.name;
mainlist.push(mnlst);
var tempArr = [];
for(var j = 0; j < obj.subs.length ; j++){
var subObj = obj.subs[j];
var sblst = subObj.name;
tempArr.push(sblst);
}
sublist[mnlst] = tempArr;
}
I've changed sublist to be an Object and I place the "subs" in to a temp array before inserting them into sublist as keyd arrays (where the key is the main name) now you can use it like sublist['main 2'] to receive all the relevant subs
Let's modify you code.
mainlist = [];
sublist = [];
for (var i = 0; i < data.mains.length; i++) {
var obj = data.mains[i];
var mnlst = obj.name;
//--[Start Modification]--
var subArr = obj.subs;
for(var j = 0; j < subArr.length; j++)
{
var subName = subArr[i].name;
//Here you have subject name, do whatever you want to do with it.
}
//--[End Modification]--
mainlist.push(mnlst);
}
console.log(mainlist);
I am having an issue returning data from a mapping.
Here is the data:
{
"id": "123",
"name": "name here",
"description": "a desc here"
"parts": [
{
"id": "432",
"name": "part name",
"stats": {
"count": 4,
},
"description": ""
},
etc....
And here's the current code:
var result = myData.map(function(value){
return [value.name, 1];
});
What I want to do it to get the count so I tried:
var result = myData.parts.map(function(value){
return [value.name.stats.count, 1];
});
But it's not returning the value of it.
What I'm I doing wrong?
You could map parts for getting the counts in an array.
counts = data.parts.map(function (o) {
return o.stats.count;
});
This question already has answers here:
Find object by id in an array of JavaScript objects
(36 answers)
Closed 6 years ago.
I have a variable which holds this data:
{"main":[
{"id":"123","name":"name 1"},
{"id":"234","name":"name 2"}
]
}
I know the id of the data I want to search.
My question is...How do I search for the name of id 234 (for example) is thw data above?
Use Array#filter
The filter() method creates a new array with all elements that pass the test implemented by the provided function.
var object = {
"main": [{
"id": "123",
"name": "name 1"
}, {
"id": "234",
"name": "name 2"
}]
};
var toFind = "234";
var filtered = object.main.filter(function(el) {
return el.id === toFind;
});
console.log(filtered);
If there is only one object in the array, for-loop with break could be preferred.
var object = {
"main": [{
"id": "123",
"name": "name 1"
}, {
"id": "234",
"name": "name 2"
}]
};
var toFind = "234";
for (var i = 0, len = object.main.length; i < len; i++) {
if (object.main[i].id === toFind) {
break;
}
}
console.log(object.main[i].name);
In ES5 environment, you could use Array#some, if you expect only one result.
var data = { "main": [{ "id": "123", "name": "name 1" }, { "id": "234", "name": "name 2" }] },
result;
data.main.some(function (a) {
if (a.id === '234') {
result = a;
return true;
}
});
console.log(result);
When you expect more than one result set, you may better use Array#filter
var data = { "main": [{ "id": "123", "name": "name 1" }, { "id": "234", "name": "name 2a" }, { "id": "234", "name": "name 2" }] },
result = data.main.filter(function (a) {
return a.id === '234';
});
console.log(result);
In ES6 environment, you could use Array#find for the first found element, but if there are more to find, then use Array#filter.
var data = { "main": [{ "id": "123", "name": "name 1" }, { "id": "234", "name": "name 2" }] },
result = data.main.find(a => a.id === '234');
console.log(result);
You can use find() if id's are unique.
var data = {"main":[
{"id":"123","name":"name 1"},
{"id":"234","name":"name 2"}
]
}
var name = data.main.find(function(o) {
return o.id == '234';
}).name;
console.log(name)
You can use Array.prototype.filter to find all matching elements and return them as a new array.
To find just the first match, you can use Array.prototype.find (ES2015+).
I'm pulling two related objects from a web service - folders and emails. Folders have an ID and a parentfolder.ID property which indicates which parent folder a folder is nested beneath. Emails have a CategoryID which indicates which folder it is a child of.
I've successfully created a function to nest the emails within a flat folder structure:
{
"folders": [
{
"name": "my emails",
"type": "folder",
"additionalParameters": {
"id": "174661",
"type": "email",
"parentID": "0"
},
"children": [
{
"name": "Test1",
"type": "item",
"additionalParameters": {
"id": "27502",
"subject": "Test"
}
},
{
"name": "Hello",
"type": "item",
"additionalParameters": {
"id": "27917",
"subject": "Hi!"
}
}
]
},
{
"name": "Test",
"type": "folder",
"additionalParameters": {
"id": "175620",
"type": "email",
"parentID": "174661"
},
"children": [
{
"name": "Test2",
"type": "item",
"additionalParameters": {
"id": "27891",
"subject": "Test"
}
}
]
},
{
"name": "SubFolder1",
"type": "folder",
"additionalParameters": {
"id": "175621",
"type": "email",
"parentID": "175620"
},
"children": [
{
"name": "Test2",
"type": "item",
"additionalParameters": {
"id": "27892",
"subject": "Test"
}
},
{
"name": "Test3",
"type": "item",
"additionalParameters": {
"id": "27893",
"subject": "Test"
}
}
]
},
{
"name": "SubFolder2",
"type": "folder",
"additionalParameters": {
"id": "175622",
"type": "email",
"parentID": "175620"
},
"children": [
{
"name": "Test4",
"type": "item",
"additionalParameters": {
"id": "27894",
"subject": "Test"
}
}
]
}
]
}
Now I need to use recursion to loop through all of the folders and push them into the children array of their parent. Essentially resorting the tree to n levels. I can disregard any type=items because they are already nested appropriately. Just need to sort those whose types are folder.
Has anyone implemented a JSON recursion function to rebuild a JSON object with nesting?
Thanks for the help.
You can do this without recursion. I answered a similar question sometime back. I believe you could use the same approach (assuming you have no forward references):
var idToNodeMap = {}; //Keeps track of nodes using id as key, for fast lookup
var root = null; //Initially set our root to null
//loop over data
for(var i = 0; i < data.folders.length; i++) {
var folder = data.folders[i];
//each node will have children, so let's give it a "children" poperty
folder.children = [];
//add an entry for this node to the map so that any future children can
//lookup the parent
idToNodeMap[folder.additionalParameters.id] = folder;
//Does this node have a parent?
if(folder.additionalParamters.parentID === "0") {
//Doesn't look like it, so this node is the root of the tree
root = folder;
} else {
//This node has a parent, so let's look it up using the id
parentNode = idToNodeMap[folder.additionalParamters.parentID];
//Let's add the current node as a child of the parent node.
parentNode.children.push(folder);
}
}
Thanks to Vivin. Via his answer I found a link to an approach that ended up working. Here's the final code:
var arr = $this.folderArray;
// Define root
console.log("arr");
console.log(arr);
// Define tree
var tree = {
root: root
};
console.log('tree');
console.log(tree);
// Get parent of node (recursive)
var getParent = function (rootNode, rootId) {
console.log('rootnode');
console.log(rootNode);
console.log('rootId');
console.log(rootId);
if (rootNode.additionalParameters.id === rootId)
return rootNode;
for (var i = 0; i < rootNode.children.length; i++) {
var child = rootNode.children[i];
if (child.additionalParameters.id === rootId) return child;
if(child.children){
if (child.children.length > 0){
var childResult = getParent(child, rootId);
if (childResult != null) return childResult;
}
}
}
return null;
};
// Traverse data and build the tree
var buildTree = function(tree) {
for (var i = 0; i < arr.length; i++) {
var elem = arr[i];
if (elem.additionalParameters.parentID === "0")
continue;
//elem["children"] = [];
var rootId = elem.additionalParameters.parentID;
var parent = getParent(tree.root, rootId);
console.log("parent");
console.log(parent);
parent.children.push(elem);
// Debug info
// console.log("Elem: " + elem.name + " with parent_id: " + elem.parentAreaRef.id);
//console.log("Got parent with name: " + parent._id);
}
};
buildTree(tree);