Merge two array of objects with nested id - javascript

I have two arrays of objects that I need to combine where the nested ID (connect.id) of the second array matches the id of the first but can't see how to do it
can anyone help?
const arr1 = [
{ "id": 7619209572755, "title": "Title 1" },
{ "id": 7619209157372, "title": "Title 2" },
{ "id": 7619209921625, "title": "Title 3" }
];
const arr2 = [
{
"id": 7619217289192,
"connect": [
{ "id": 7619209157372, "title": "Title 1" }
],
"value": "1"
},
{
"id": 7619217242206,
"connect": [
{ "id": 7619209921625, "title": "Title 2" }
],
"value": "2"
}
];
const expectedResult = [
{ "id": 7619209572755, "title": "Title 1" },
{ "id": 7619209157372, "title": "Title 2", "value": "1" },
{ "id": 7619209921625, "title": "Title 3", "value": "2" }
]

Using Array#reduce, iterate over arr2 to map every connect element's id with the its object's value in a Map
Using Array#map, iterate over arr1, if an element's id is in the map, set its value
const
arr1 = [ { "id": 7619209572755, "title": "Title 1" }, { "id": 7619209157372, "title": "Title 2" }, { "id": 7619209921625, "title": "Title 3" } ],
arr2 = [
{
"id": 7619217289192,
"connect": [ { "id": 7619209157372, "title": "Title 1" } ],
"value": "1",
},
{
"id": 7619217242206,
"connect": [ { "id": 7619209921625, "title": "Title 2" } ],
"value": "2",
}
];
const connectValueMap = arr2.reduce((map, { connect = [], value}) => {
connect.forEach(({ id }) => map.set(id, value));
return map;
}, new Map);
const merged = arr1.map(e => {
const value = connectValueMap.get(e.id);
if(value) e.value = value;
return e;
});
console.log(merged);

Related

Is this the best approach to restructure an array and reorganize it based off a sub array's value

I have the below array which has a sub array of categories, I would like to output the array over and over but grouping the items into another array based on their related categories
testData2: any = [{
"id": 0,
"name": "XyZ",
"category": [ {
"title": "horse"
}, {
"title": "food"
}]
}, {
"id": 2,
"name": "something 2",
"category": [{
"title": "fishing"
}, {
"title": "horse"
}, {
"title": "food"
}]
},
{
"id": 3,
"name": "something 3",
"category": [{
"title": "horse"
}]
}, {
"id": 4,
"name": "something 4",
"category": [{
"title": "food"
}, {
"title": "beer"
}]
}, {
"id": 5,
"name": "something 4",
"category": [{
"title": "fishing"
}]
}
]
So far I have this which works, but i cant help wonder if there is some new JS magic which may be more perfomant to accomplish this ?
let newArray = [];
for (let x = 0; x < this.testData2.length; x++) {
let parent = this.testData2[x];
let child = parent.category;
for (let y = 0; y < child.length; y++) {
let cat = child[y];
let format = parent
newArray.push({ group_heading: cat.title, services: [format] })
}
}
let finalOutput = newArray.reduce((acc, curr) => {
const ndx = acc.findIndex((e: any) => e.group_heading === curr.group_heading);
if(ndx > -1){
acc[ndx].services.push(...curr.services)
} else{
acc.push(curr)
}
return acc;
}, [])
which outputs this as desired
[{
"group_heading": "horse",
"services": [{
"id": 0,
"name": "XyZ",
"category": [{
"title": "horse"
}, {
"title": "food"
}]
}, {
"id": 2,
"name": "something 2",
"category": [{
"title": "fishing"
}, {
"title": "horse"
}, {
"title": "food"
}]
}, {
"id": 3,
"name": "something 3",
"category": [{
"title": "horse"
}]
}]
}, {
"group_heading": "food",
"services": [{
"id": 0,
"name": "XyZ",
"category": [{
"title": "horse"
}, {
"title": "food"
}]
}, {
"id": 2,
"name": "something 2",
"category": [{
"title": "fishing"
}, {
"title": "horse"
}, {
"title": "food"
}]
}, {
"id": 4,
"name": "something 4",
"category": [{
"title": "food"
}, {
"title": "beer"
}]
}]
}, {
"group_heading": "fishing",
"services": [{
"id": 2,
"name": "something 2",
"category": [{
"title": "fishing"
}, {
"title": "horse"
}, {
"title": "food"
}]
}, {
"id": 5,
"name": "something 4",
"category": [{
"title": "fishing"
}]
}]
}, {
"group_heading": "beer",
"services": [{
"id": 4,
"name": "something 4",
"category": [{
"title": "food"
}, {
"title": "beer"
}]
}]
}]
I would probably do something like this:
// first collect services by category
const servicesByCategory = {}
for(const service of testData2){
for(const {title} of service.category){
if(!servicesByCategory[title]){
servicesByCategory[title] = []
}
servicesByCategory[title].push(data)
}
}
// whip it into whatever form you need
return Object.entries(servicesByCategory)
.map(([group_headings, services]) => ({group_headings, services}))

Deleting All the similar object from array if it has duplicates

I have an array of objects with duplicates:
[
{
"code": "d1",
"title": "Title 1"
},
{
"code": "d2",
"title": "Title 2"
},
{
"code": "d3",
"title": "Title 3"
},
{
"code": "d4",
"title": "Title 4"
},
{
"code": "d4",
"title": "Title 4"
},
{
"code": "d3",
"title": "Title 3"
}
]
So i want the output to be having only the once which doesn't have duplicates included like below:
[
{
"code": "d1",
"title": "Title 1"
},
{
"code": "d2",
"title": "Title 2"
}
]
Any help would be appreciated, Thanks!
Find unique's values in an array.
const ressult = YourArray.filter(
(value, index, array) => array.findIndex((v) => v.code === value.code) === index
);
Here is one way of doing it:
const products=[
{
"code": "d1",
"title": "Title 1"
},
{
"code": "d2",
"title": "Title 2"
},
{
"code": "d3",
"title": "Title 3"
},
{
"code": "d4",
"title": "Title 4"
},
{
"code": "d4",
"title": "Title 4"
},
{
"code": "d3",
"title": "Title 3"
}
];
const res=Object.entries(products.reduce((a,c)=>{
(a[c.code+"|"+c.title]??=[]).push(c);
return a;
},{})).reduce((a,[k,v])=>{
if(v.length==1) a.push(v[0]);
return a;
},[]);
console.log(res);
My approach involves two .reduce() loops:
In the first one I generate an object that collects all elements of the original array behind a compound key made up of the properties of the elements.
the object is then converted into an array again with Object.entries()
and in a second .reduce() only those elements will be collected (i. e.: their first element) into the target array that have a length of 1
let val = [
{
"code": "d1",
"title": "Title 1"
},
{
"code": "d2",
"title": "Title 2"
},
{
"code": "d3",
"title": "Title 3"
},
{
"code": "d4",
"title": "Title 4"
},
{
"code": "d4",
"title": "Title 4"
},
{
"code": "d3",
"title": "Title 3"
}
];
let distinctVal = getDistincts(val);
function getDistincts(val){
let obj={};
for (let i = 0; i < val.length; i++) {
obj[`${val[i]["code"]}`]=val[i]["title"];
}
return obj;
}
console.log(distinctVal);

Get nearest parent object in nested array

I have the following array:
const items = [
{
"id": 1,
"name": "Menu 1",
"content": [
{
"id": 2,
"name": "Submenu 1 OF 1",
"url": "teste"
}
]
},
{
"id": 3,
"name": "Menu 2",
"content": [
{
"id": 4,
"name": "Submenu 1 OF 2",
"url": "teste"
},
{
"id": 5,
"name": "Submenu 2 OF 2",
"content": [
{
"id": 6,
"name": "Sub submenu 1 OF 2",
"url": "teste"
},
{
"id": 7,
"name": "Sub submenu 2 OF 2",
"url": "teste"
},
]
}
]
}
]
I need a function that given the id gets the closest parent object. For example, if I give the id 2 it returns {"id: 1, "name": "Menu 1", "content": [...]}. If I give the id 6 it returns {"id": 5, "name": "Submenu 2 OF 2", content: [...]}.
I have tried but i can only get the top-level parent and not the closest one.
EDIT: the code that i have tested so far:
let findDeep = function(data, id) {
return data.find(function(e) {
if(e.id == id) return e;
else if(e.content) return findDeep(e.content, id);
}
})
You can use a recursive depth-first search:
function findParent(items, id, parent=null) {
for (let item of items) {
let res = item.id === id ? parent
: item.content && findParent(item.content, id, item);
if (res) return res;
}
}
// demo: find parent of id=6 in example tree:
const items = [{"id": 1,"name": "Menu 1","content": [{"id": 2,"name": "Submenu 1 OF 1","url": "teste"}]},{"id": 3,"name": "Menu 2","content": [{"id": 4,"name": "Submenu 1 OF 2","url": "teste"},{"id": 5,"name": "Submenu 2 OF 2","content": [{"id": 6,"name": "Sub submenu 1 OF 2","url": "teste"},{"id": 7,"name": "Sub submenu 2 OF 2","url": "teste"},]}]}]
console.log(findParent(items, 6));
You can do this with a recursive function that checks each child and returns the parent if the id matches:
const findParent = (id, obj) => {
for (const child of obj.content) {
if (child.id === id) return obj;
if (!child.content) continue;
const found = findParent(id, child);
if (found) return found;
}
return undefined;
}
const items = {content: [{
"id": 1,
"name": "Menu 1",
"content": [{
"id": 2,
"name": "Submenu 1 OF 1",
"url": "teste"
}]
},
{
"id": 3,
"name": "Menu 2",
"content": [{
"id": 4,
"name": "Submenu 1 OF 2",
"url": "teste"
},
{
"id": 5,
"name": "Submenu 2 OF 2",
"content": [{
"id": 6,
"name": "Sub submenu 1 OF 2",
"url": "teste"
},
{
"id": 7,
"name": "Sub submenu 2 OF 2",
"url": "teste"
},
]
}
]
}
]
}
console.log(findParent(2, items));
console.log(findParent(6, items));

Iterate through each object array based on condition check

I have a scenario were I need to iterate through each parent/child array in an object.
Each Grandparents can have multiple parents, in same fashion each parent can have multiple childs, each child can have multiple subChilds and so on.
I need to check if type is "parent" or "child" while iterating and then push name property to an array as mentioned in expected output.
Input Object:
var inputObject = {
"id": 1,
"name": "Grand Parent 1",
"type": "GrandParent",
"childType": [
{
"id": 2,
"type": "Parent",
"childType": [
{
"id": 3,
"type": "Child",
"childType": [],
"name": "Child 11"
},
{
"id": 4,
"type": "Child",
"childType": [],
"name": "Child 12"
}
],
"name": "Parent 1"
},
{
"id": 5,
"type": "Parent",
"childType": [
{
"id": 6,
"type": "Child",
"childType": [],
"name": "Child 21"
}
],
"name": "Parent 2"
},
{
"id": 7,
"type": "Parent",
"childType": [
{
"id": 8,
"type": "Child",
"childType": [],
"name": "Child 31"
}
],
"name": "Parent 3"
}
]
}
Code Tried:
function handleData({childType, ...rest}){
const res = [];
res.push(rest.name);
if(childType){
if(rest.type == "Child")
res.push(...handleData(childType));
}
return res;
}
const res = handleData(inputObject);
Expected Output:
If type selected is "Parent"
["Parent 1", "Parent 2, Parent 3"]
if type selected is "Child"
["Child 11", "Child 12", "Child 21", "Child 31"]
You can do a recursive function that uses flatMap():
const obj = {id:1,name:"Grand Parent 1",type:"GrandParent",childType:[{id:2,type:"Parent",childType:[{id:3,type:"Child",childType:[],name:"Child 11"},{id:4,type:"Child",childType:[],name:"Child 12"}],name:"Parent 1"},{id:5,type:"Parent",childType:[{id:6,type:"Child",childType:[],name:"Child 21"}],name:"Parent 2"},{id:7,type:"Parent",childType:[{id:8,type:"Child",childType:[],name:"Child 31"}],name:"Parent 3"}]};
const get = (o, t) => o.type === t ? [o.name] : o.childType.flatMap(c => get(c, t));
console.log(get(obj, 'GrandParent'));
console.log(get(obj, 'Parent'));
console.log(get(obj, 'Child'));
You can do that using recursion.
Steps:
Create a wrapper function in which you declare result array.
Inside that make a wrapper function create a function which would be called recursively
Check if type matches the given type add the name of object to result
Then check if elements exists in its childType. If yes yes then call function on each each of its element.
var inputObject = { "id": 1, "name": "Grand Parent 1", "type": "GrandParent", "childType": [ { "id": 2, "type": "Parent", "childType": [ { "id": 3, "type": "Child", "childType": [], "name": "Child 11" }, { "id": 4, "type": "Child", "childType": [], "name": "Child 12" } ], "name": "Parent 1" }, { "id": 5, "type": "Parent", "childType": [ { "id": 6, "type": "Child", "childType": [], "name": "Child 21" } ], "name": "Parent 2" }, { "id": 7, "type": "Parent", "childType": [ { "id": 8, "type": "Child", "childType": [], "name": "Child 31" } ], "name": "Parent 3" } ] }
function handleData(obj,type){
let res = [];
function recursive(obj){
if(type === obj.type) res.push(obj.name);
if(obj.childType.length){
obj.childType.forEach(a => recursive(a));
}
}
recursive(obj)
return res;
}
console.log(handleData(inputObject,"Child"))
console.log(handleData(inputObject,"Parent"))
Recursion is elegant but you could use es6 to do it , if the object childType was very large, recursion might not be applicable (stack overflow), here is a solution using reduce,
function getType({childType}, type) {
return childType.reduce( (acc, {type: objectType, name}) => {
if (objectType === type){
acc.push(name)
}
return acc
}, [])
}
You can solve this problem using recursion. You can try on this way !
var inputObject = {
"id": 1,
"name": "Grand Parent 1",
"type": "GrandParent",
"childType": [
{
"id": 2,
"type": "Parent",
"childType": [
{
"id": 3,
"type": "Child",
"childType": [],
"name": "Child 11"
},
{
"id": 4,
"type": "Child",
"childType": [],
"name": "Child 12"
}
],
"name": "Parent 1"
},
{
"id": 5,
"type": "Parent",
"childType": [
{
"id": 6,
"type": "Child",
"childType": [],
"name": "Child 21"
}
],
"name": "Parent 2"
},
{
"id": 7,
"type": "Parent",
"childType": [
{
"id": 8,
"type": "Child",
"childType": [],
"name": "Child 31"
}
],
"name": "Parent 3"
}
]
};
var resultValues = [];
function getResult(inputObject, propertyName, propertyValue) {
for (var objectProperty in inputObject) {
if (objectProperty == propertyName && inputObject[objectProperty] == propertyValue) {
resultValues.push(inputObject['name']);
console.log(resultValues);
} else {
if (objectProperty == 'childType') {
inputObject[objectProperty].forEach(function (element) {
getResult(element, propertyName, propertyValue)
});
}
}
}
//console.log(resultValues);
}
getResult(inputObject, 'type', 'GrandParent');
getResult(inputObject, 'type', 'Parent');
getResult(inputObject, 'type', 'Child');

Do I need to convert this Array in Objects?

My data is an array that I'm converting into a key:value (not sure if this is what it's called) type.
Data:
[
{
"id": 1,
"title": "Name 01",
"tags": [
"TAG1",
"TAG4",
"TAG2"
]
},
{
"id": 2,
"title": "Name 02",
"tags": [
"TAG4",
"TAG3"
]
},
{
"id": 3,
"title": "Name 03",
"tags": [
"TAG1"
]
}
]
I'm converting this into :
result = data.map(a => ({ [a.id]: a }));
So I'm getting:
Result:
[
{
"1": {
"id": 1,
"title": "Post1 T1 T2 T4",
"tags": [
"TAG1",
"TAG4",
"TAG2"
]
}
},
{
"2": {
"id": 2,
"title": "Post1 T3 T4",
"tags": [
"TAG4",
"TAG3"
]
}
},
{
"3": {
"id": 3,
"title": "Post3 with No Tags",
"tags": [
"TAG1"
]
}
}
]
How can I map the results and show in a View/Text?
I tried:
Object.keys(results).map((result, idx) => {
return(
<View key={idx}>
<Text>{result.title}</Text>
</View>
)
});
But I'm getting an error : Cannot read property 'map' of undefined.
Do I need to convert the results to an object and only then I'll be able to use Object.keys. If yes, how do I convert the entire result in an Object like this:
Results:
{
{
"1": {
"id": 1,
"title": "Post1 T1 T2 T4",
"tags": [
"TAG1",
"TAG4",
"TAG2"
]
}
},
{
"2": {
"id": 2,
"title": "Post1 T3 T4",
"tags": [
"TAG4",
"TAG3"
]
}
},
{
"3": {
"id": 3,
"title": "Post3 with No Tags",
"tags": [
"TAG1"
]
}
}
}
The reason I'm doing this is to target the id for a reducer dispatched action:
switch (action.type) {
case "INC_NUM":
const newState = {...state};
newState[action.payload].nubmer++;
return newState;
It sounds like you just want to be able to quickly find the object that has a given id value. Rather than "convert" your data, I'd suggest you just make a map so you can look up any object by id.
let data = [
{
"id": 1,
"title": "Name 01",
"tags": [
"TAG1",
"TAG4",
"TAG2"
]
},
{
"id": 2,
"title": "Name 02",
"tags": [
"TAG4",
"TAG3"
]
},
{
"id": 3,
"title": "Name 03",
"tags": [
"TAG1"
]
}
];
// create a map with id as the key, object as the value
let map = new Map();
data.forEach(obj => {
map.set(obj.id, obj);
});
// look up a given id
console.log(map.get(3));

Categories