How to make the property of one array property of another (code optimization) - javascript

That's what I have
const users = [
{ id: 1, name: 'Mike', postIds: [11, 22] },
{ id: 2, name: 'Dan', postIds: [33] },
{ id: 3, name: 'Lance', postIds: [44] },
];
const posts = [
{ id: 11, title: 'How good is he' },
{ id: 22, title: 'How fast is he' },
{ id: 33, title: 'How to make it faster' },
{ id: 44, title: 'How can he do it' },
];
That's what I need to get in the output
const expectedResult = [
{
id: 1,
name: 'Mike',
posts: [
{ id: 11, title: 'How good is he' },
{ id: 22, title: 'How fast is he' },
]
},
{
id: 2,
name: 'Dan',
posts: [{ id: 33, title: 'How to make it faster' }]
},
{
id: 3,
name: 'Lance',
posts: [{ id: 44, title: 'How can he do it' }]
},
]
That's what I tried. It works, but it's stupid and I think it can be done in one operation. Please check what can I do make to it cleaner
const users = [
{ id: 1, name: 'Mike', postIds: [11, 22] },
{ id: 2, name: 'Dan', postIds: [33] },
{ id: 3, name: 'Lance', postIds: [44] },
];
const posts = [
{ id: 11, title: 'How good is he' },
{ id: 22, title: 'How fast is he' },
{ id: 33, title: 'How to make it faster' },
{ id: 44, title: 'How can he do it' },
];
let updUsers = users.map(obj => ({ ...obj,
posts: [...posts]
}))
const output = updUsers.map(
user => ({
...user,
posts: user.posts.filter(
post => user.postIds.includes(post.id)
)
})
);
const expectedOut = output.map(({
id,
name,
posts
}) => ({
id,
name,
posts
}))
console.log(expOut)

Turn the posts array into a mapping of post ID -> post object for faster lookup:
const postMap = new Map(posts.map((p) => [p.id, p]));
const expectedResult = users.map((u) => {
const newU = { ...u, posts: u.postIds.map((id) => postMap.get(id)) };
delete newU.postIds; // Remove the undesired `postIds` property from the copy
return newU;
});
console.log(expectedResult);

You can filter posts when you're mapping users rather than doing it as a second pass.
const users = [
{ id: 1, name: 'Mike', postIds: [11, 22] },
{ id: 2, name: 'Dan', postIds: [33] },
{ id: 3, name: 'Lance', postIds: [44] },
];
const posts = [
{ id: 11, title: 'How good is he' },
{ id: 22, title: 'How fast is he' },
{ id: 33, title: 'How to make it faster' },
{ id: 44, title: 'How can he do it' },
];
let expOut = users.map(({id, name, postIds}) => ({ id, name,
posts: posts.filter(({id}) => postIds.includes(id))
}))
console.log(expOut)

This is another naive method but time complexity is more.
P.S.: Time complexity is n^3
const users = [
{ id: 1, name: 'Mike', postIds: [11, 22] },
{ id: 2, name: 'Dan', postIds: [33] },
{ id: 3, name: 'Lance', postIds: [44] },
];
const posts = [
{ id: 11, title: 'How good is he' },
{ id: 22, title: 'How fast is he' },
{ id: 33, title: 'How to make it faster' },
{ id: 44, title: 'How can he do it' },
];
let updUsers = users.map(function(obj){
let postsArr = [];
for(i=0; i<obj.postIds.length; i++){
const postArr = posts.find((item) => item.id == obj.postIds[i]);
postsArr.push(postArr);
};
return{'id':obj.id,'name':obj.name,'posts':postsArr};});
console.log(updUsers);

You can first convert your posts array to key value pairs and take object using Object.fromEntries, now just map it. Here is an implementation:
const users = [ { id: 1, name: 'Mike', postIds: [11, 22] }, { id: 2, name: 'Dan', postIds: [33] }, { id: 3, name: 'Lance', postIds: [44] },];
const posts = [ { id: 11, title: 'How good is he' }, { id: 22, title: 'How fast is he' }, { id: 33, title: 'How to make it faster' }, { id: 44, title: 'How can he do it' },];
//convert posts to object and then map it:
const postObjects = Object.fromEntries(posts.map(p=>[p.id, p]));
const result = users.map(({id, name, postIds})=>({id, name, posts:postIds.map(p=>postObjects[p])}));
console.log(result);

We can simplify this using Array.prototype.reduce and Array.prototype..filter and use a Set for finding the right posts for a user for faster lookup:
const users = [
{ id: 1, name: 'Mike', postIds: [11, 22] },
{ id: 2, name: 'Dan', postIds: [33] },
{ id: 3, name: 'Lance', postIds: [44] },
];
const posts = [
{ id: 11, title: 'How good is he' },
{ id: 22, title: 'How fast is he' },
{ id: 33, title: 'How to make it faster' },
{ id: 44, title: 'How can he do it' },
];
const mapUsersByPost = (users, posts) => {
return users.reduce((acc, {id, name, postIds}) => {
const filteredPosts = posts.filter(({id}) => new Set(postIds).has(id));
acc.push({ id, name, posts: filteredPosts});
return acc;
}, []);
}
console.log(mapUsersByPost(users, posts));

Related

How can I get the result from arr1 and arr2, When the ID matches I need to copy the content from arr1

How can I get the result from arr1 and arr2, When the ID matches I need to copy the content from arr1
const arr1 = [
{ id: 1, name: "omar" },
{ id: 2, name: "laith" },
{ id: 3, name: "aref" },
]
const arr2 = [
{ id: 1, rating: "good" },
{ id: 2, rating: "very good" },
{ id: 2, rating: "very good" },
{ id: 3, rating: "Excellence" },
{ id: 3, rating: "Excellence" },
]
//expected output
const result = [
{ id: 1, rating: "good", name: "omar" },
{ id: 1, rating: "good", name: "omar" },
{ id: 2, rating: "very good", name: "laith" },
{ id: 3, rating: "Excellence", name: "aref" },
{ id: 3, rating: "Excellence", name: "aref" },
]
use reduce with filter
const arr1 = [ { id: 1, name: "omar" }, { id: 2, name: "laith" }, { id: 3, name: "aref" }, ];
const arr2 = [ { id: 1, rating: "good" }, { id: 2, rating: "very good" }, { id: 2, rating: "very good" }, { id: 3, rating: "Excellence" }, { id: 3, rating: "Excellence" }, ];
const result = arr1.reduce((acc,item) => {
const list = arr2.filter(i => i.id === item.id)
return [...acc, ...list.map(i => ({id: i.id,rating:i.rating, name: item.name}))]
}, [])
console.log(result)
Basically with a loop. Actually 2. Using a temporary object (result) as dictionary (or map) we can make it efficient searching for a match to each id. This is of complexity O(n) basically.
const arr1 = [ { id: 1, name: "omar" }, { id: 2, name: "laith" }, { id: 3, name: "aref" }, ];
const arr2 = [ { id: 1, rating: "good" }, { id: 2, rating: "very good" }, { id: 2, rating: "very good" }, { id: 3, rating: "Excellence" }, { id: 3, rating: "Excellence" }, ];
var result = {}
arr1.forEach(function(item1) {
result[item1.id] = item1;
});
arr2.forEach(function(item2) {
result[item2.id] = (result[item2.id] || item2)
result[item2.id]['rating'] = item2.rating
})
result = Object.values(result)
console.log(result)

find method not returning '0th' matched object react, or react-native or javascript

Not getting all matched objects, its is returning all objects except '{ ID:0, Name: 'General Group' }', i want all matched objects
let arrDashboardIconGroups = [
{ ID:0, Name: 'General Group' },
{ ID: 1, Name: 'Patient Administration' },
{ ID: 2, Name: 'Medical Charts' },
{ ID: 3, Name: 'Medical Procedures' },
{ ID: 13, Name: 'Purchase' },
{ ID: 14, Name: 'Sales' },
{ ID: 5, Name: 'Insurance' },
{ ID: 4, Name: 'Cash' },
{ ID: 6, Name: 'Pharmacy' },
{ ID: 7, Name: 'Inventory' },
{ ID: 8, Name: 'Lab' },
{ ID: 9, Name: 'Imaging' },
{ ID: 10, Name: 'In Patient' },
{ ID: 11, Name: 'System Administration' },
{ ID: 12, Name: 'Accounting' }
]
const getMatchedobjects=()=> {
let result = [0,1,2,3,4,]
let matchedArray = arrDashboardIconGroups.filter(val =>result.find(
(items)=>items == val.ID))
console.log(matchedArray)
}
getMatchedobjects()
You are returning the value of
result.find((items) => items == val.ID)
In the first case, the value returned is 0 which is a falsy value. So It won't include in the final filter result.
You can run the below code and see the returning values.
let arrDashboardIconGroups = [
{ ID: 0, Name: "General Group" },
{ ID: 1, Name: "Patient Administration" },
{ ID: 2, Name: "Medical Charts" },
{ ID: 3, Name: "Medical Procedures" },
{ ID: 13, Name: "Purchase" },
{ ID: 14, Name: "Sales" },
{ ID: 5, Name: "Insurance" },
{ ID: 4, Name: "Cash" },
{ ID: 6, Name: "Pharmacy" },
{ ID: 7, Name: "Inventory" },
{ ID: 8, Name: "Lab" },
{ ID: 9, Name: "Imaging" },
{ ID: 10, Name: "In Patient" },
{ ID: 11, Name: "System Administration" },
{ ID: 12, Name: "Accounting" },
];
const getMatchedobjects = () => {
let result = [0, 1, 2, 3, 4];
let matchedArray = arrDashboardIconGroups.filter((val) => {
const returnResult = result.find((items) => items == val.ID);
console.log(returnResult);
return returnResult;
// result.includes(val.ID)
});
console.log(matchedArray);
};
getMatchedobjects();
Alternatively, you can use includes
let arrDashboardIconGroups = [
{ ID: 0, Name: "General Group" },
{ ID: 1, Name: "Patient Administration" },
{ ID: 2, Name: "Medical Charts" },
{ ID: 3, Name: "Medical Procedures" },
{ ID: 13, Name: "Purchase" },
{ ID: 14, Name: "Sales" },
{ ID: 5, Name: "Insurance" },
{ ID: 4, Name: "Cash" },
{ ID: 6, Name: "Pharmacy" },
{ ID: 7, Name: "Inventory" },
{ ID: 8, Name: "Lab" },
{ ID: 9, Name: "Imaging" },
{ ID: 10, Name: "In Patient" },
{ ID: 11, Name: "System Administration" },
{ ID: 12, Name: "Accounting" },
];
const getMatchedobjects = () => {
let result = [0, 1, 2, 3, 4];
let matchedArray = arrDashboardIconGroups.filter((val) => result.includes(val.ID));
console.log(matchedArray);
};
getMatchedobjects();
Issue
Find returns a value/object (the first matching), but it seems you want to filter the arrDashboardIconGroups array by those that match an id specified in the result array. When result[0] is returned, 0 is the value, which is falsey, and the filter doesn't return the element from the arrDashboardIconGroups array.
Solution
Use Array.prototype.some to return the boolean that filter needs to include an element in the result array.
let arrDashboardIconGroups = [
{ ID:0, Name: 'General Group' },
{ ID: 1, Name: 'Patient Administration' },
{ ID: 2, Name: 'Medical Charts' },
{ ID: 3, Name: 'Medical Procedures' },
{ ID: 13, Name: 'Purchase' },
{ ID: 14, Name: 'Sales' },
{ ID: 5, Name: 'Insurance' },
{ ID: 4, Name: 'Cash' },
{ ID: 6, Name: 'Pharmacy' },
{ ID: 7, Name: 'Inventory' },
{ ID: 8, Name: 'Lab' },
{ ID: 9, Name: 'Imaging' },
{ ID: 10, Name: 'In Patient' },
{ ID: 11, Name: 'System Administration' },
{ ID: 12, Name: 'Accounting' }
];
const getMatchedobjects = () => {
let result = [0,1,2,3,4,];
let matchedArray = arrDashboardIconGroups.filter(val => result.some((items)=>items == val.ID));
console.log(matchedArray);
}
getMatchedobjects();
Alternatively you could also check that result array includes the matching id.
let arrDashboardIconGroups = [
{ ID:0, Name: 'General Group' },
{ ID: 1, Name: 'Patient Administration' },
{ ID: 2, Name: 'Medical Charts' },
{ ID: 3, Name: 'Medical Procedures' },
{ ID: 13, Name: 'Purchase' },
{ ID: 14, Name: 'Sales' },
{ ID: 5, Name: 'Insurance' },
{ ID: 4, Name: 'Cash' },
{ ID: 6, Name: 'Pharmacy' },
{ ID: 7, Name: 'Inventory' },
{ ID: 8, Name: 'Lab' },
{ ID: 9, Name: 'Imaging' },
{ ID: 10, Name: 'In Patient' },
{ ID: 11, Name: 'System Administration' },
{ ID: 12, Name: 'Accounting' }
];
const getMatchedobjects=()=> {
let result = [0,1,2,3,4,];
let matchedArray = arrDashboardIconGroups.filter(val => result.includes(val.ID)) ;
console.log(matchedArray);
}
getMatchedobjects();
find() returns value of the first element in the provided array that satisfies the provided testing function. Since 0 is a falsy value, it does not include it in the final array. See MDN Docs
You can map the result array, and use arrDashboardIconGroups's find function, and return the matching objects.
let arrDashboardIconGroups = [
{ ID: 0, Name: 'General Group' },
{ ID: 1, Name: 'Patient Administration' },
{ ID: 2, Name: 'Medical Charts' },
{ ID: 3, Name: 'Medical Procedures' },
{ ID: 13, Name: 'Purchase' },
{ ID: 14, Name: 'Sales' },
{ ID: 5, Name: 'Insurance' },
{ ID: 4, Name: 'Cash' },
{ ID: 6, Name: 'Pharmacy' },
{ ID: 7, Name: 'Inventory' },
{ ID: 8, Name: 'Lab' },
{ ID: 9, Name: 'Imaging' },
{ ID: 10, Name: 'In Patient' },
{ ID: 11, Name: 'System Administration' },
{ ID: 12, Name: 'Accounting' }
]
const getMatchedobjects=()=> {
let result = [0, 1,2,3,4,99] //99 for trial
let matchedArray = result.map((res)=>arrDashboardIconGroups.find((val)=>val.ID == res)).filter(Boolean);
console.log(matchedArray)
}
getMatchedobjects()

How to flatten the nested Array?

How do I flatten the nested Array in the Array?
Here is the example input Array,
const input = [
{
id: 1,
name: 'Charles',
otherFields: [{
id: 2,
name: 'Pung',
}, {
id: 3,
name: 'James',
}]
}, {
id: 4,
name: 'Charles',
otherFields: [{
id: 5,
name: 'Pung',
}, {
id: 6,
name: 'James',
}]
}
]
Output Array I want to get.
[{
id: 1,
name: 'Charles'
}, {
id: 2,
name: 'Pung',
}, {
id: 3,
name: 'James',
}, {
id: 4,
name: 'Charles'
}, {
id: 5,
name: 'Pung',
}, {
id: 6,
name: 'James',
}]
I want to somehow get the output in one statement like
input.map((sth) => ({...sth??, sth.field...})); // I'm not sure :(
With flatMap you can take out the otherFields property, and returning an array containing the parent item and the other array:
const input = [{
id: 1,
name: 'Charles',
otherFields: [{
id: 2,
name: 'Pung',
}, {
id: 3,
name: 'James',
}]
}];
console.log(
input.flatMap(({ otherFields, ...item }) => [item, ...otherFields])
);
For more than one level, you could take a recursive approach of flattening.
const
flat = ({ otherFields = [], ...o }) => [o, ...otherFields.flatMap(flat)],
input = [{ id: 1, name: 'Charles', otherFields: [{ id: 2, name: 'Pung' }, { id: 3, name: 'James', otherFields: [{ id: 4, name: 'Jane' }] }] }],
result = input.flatMap(flat);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

How can I filter specific object value by the parameter of another object value

This is the input. In the "posts" property, I have all of the posts. I need to filter the posts by "postIds" property.
const users = [
{ id: 1, name: 'Dan', postIds: [11, 22],posts:[
{ id: 11, title: 'How to make it fast' },
{ id: 22, title: 'How to make it clearly' },
{ id: 33, title: 'How to can I do it' },
{ id: 44, title: 'How to he can do it' },
]} ,
{ id: 2, name: 'Mike', postIds: [33], posts:[
{ id: 11, title: 'How to make it fast' },
{ id: 22, title: 'How to make it clearly' },
{ id: 33, title: 'How to can I do it' },
{ id: 44, title: 'How to he can do it' },
]},
{ id: 3, name: 'Lola', postIds: [44], posts: [
{ id: 11, title: 'How to make it fast' },
{ id: 22, title: 'How to make it clearly' },
{ id: 33, title: 'How to can I do it' },
{ id: 44, title: 'How to he can do it' },
]}
This is how the output should look alike:
const users = [
{ id: 1, name: 'Dan', postIds: [11, 22],posts:[
{ id: 11, title: 'How to make it fast' },
{ id: 22, title: 'How to make it clearly' },
] ,
{ id: 2, name: 'Mike', postIds: [33], posts:[
{ id: 33, title: 'How to can I do it' },
]},
{ id: 3, name: 'Lola', postIds: [44], posts: [
{ id: 44, title: 'How to he can do it' },
]}
I do believe that I have to work with "filter" and "some", but the option that I tried is not relevantly working:
const filterUserPosts = users.filter(obj=>obj.posts.id===obj.some(postIds))
What is the best option?
The array you want to filter is obj.posts, not updUsers (which I assume is the same as users).
You need to loop over users to filter each of their posts properties.
You can use includes() to tell if the id of the post is in postIds.
const users = [
{ id: 1, name: 'Dan', postIds: [11, 22],posts:[
{ id: 11, title: 'How to make it fast' },
{ id: 22, title: 'How to make it clearly' },
{ id: 33, title: 'How to can I do it' },
{ id: 44, title: 'How to he can do it' },
]} ,
{ id: 2, name: 'Mike', postIds: [33], posts:[
{ id: 11, title: 'How to make it fast' },
{ id: 22, title: 'How to make it clearly' },
{ id: 33, title: 'How to can I do it' },
{ id: 44, title: 'How to he can do it' },
]},
{ id: 3, name: 'Lola', postIds: [44], posts: [
{ id: 11, title: 'How to make it fast' },
{ id: 22, title: 'How to make it clearly' },
{ id: 33, title: 'How to can I do it' },
{ id: 44, title: 'How to he can do it' },
]}];
users.forEach(u => u.posts = u.posts.filter(p => u.postIds.includes(p.id)));
console.log(users);
You need to save the postIds array somewhere first, then call .filter on the posts array, filtering by whether the element being iterated over has an ID in the postIds:
const users = [
{ id: 1, name: 'Dan', postIds: [11, 22],posts:[
{ id: 11, title: 'How to make it fast' },
{ id: 22, title: 'How to make it clearly' },
{ id: 33, title: 'How to can I do it' },
{ id: 44, title: 'How to he can do it' },
]} ,
{ id: 2, name: 'Mike', postIds: [33], posts:[
{ id: 11, title: 'How to make it fast' },
{ id: 22, title: 'How to make it clearly' },
{ id: 33, title: 'How to can I do it' },
{ id: 44, title: 'How to he can do it' },
]},
{ id: 3, name: 'Lola', postIds: [44], posts: [
{ id: 11, title: 'How to make it fast' },
{ id: 22, title: 'How to make it clearly' },
{ id: 33, title: 'How to can I do it' },
{ id: 44, title: 'How to he can do it' },]}
]
const output = users.map(
user => ({
...user,
posts: user.posts.filter(
post => user.postIds.includes(post.id)
)
})
);
console.log(output);
Try this:
const usersWithFilteredPosts = users.map((user) => ({
...user,
posts: user.posts.filter(({ id }) => user.postIds.includes(id)),
}));

GroupBy with Multiple Columns using Lodash or Underscore in Javascript

Getting Problem while converting JSON structure. My JSON Structure is as below.
const member = [{
memberId: 4,
memberName: 'ABC',
age: 22,
eventId: 5,
eventName: 'Dance'
},
{
memberId: 4,
memberName: 'ABC',
age: 22,
eventId: 6,
eventName: 'Music'
},
{
memberId: 4,
memberName: 'ABC',
age: 22,
eventId: 7,
eventName: 'FootBall'
},
{
memberId: 5,
memberName: 'PQR',
age: 24,
eventId: 6,
eventName: 'Music'
},
{
memberId: 5,
memberName: 'PQR',
age: 24,
eventId: 5,
eventName: 'Dance'
},
]
Here I have two members with associated events. And I want to convert JSON as follows.
const member = [
{
memberId: 4,
memberName: 'ABC',
age: 22,
events: [
{
id: 5,
name: 'Dance'
},
{
id: 6,
name: 'Music'
},
{
id: 7,
name: 'FootBall'
}
]
},
{
memberId: 5,
memberName: 'PQR',
age: 24,
events: [
{
id: 6,
name: 'Music'
},
{
id: 5,
name: 'Dance'
}
]
}
]
I tried creating the structure using below code but it doesn't provide as the desired output. It just creates two Key-Value pair.
var result = _.chain(member)
.groupBy("memberId")
.pairs()
.map(function(currentItem) {
return _.object(_.zip(["memberId", "events"], currentItem));
})
.value();
I don't know how to add other values of JSON in the hierarchy.
After you group the items, map them. Take the 1st item of each group, and remove the event properties, and spread it. To get the the events data, map the group's items and take only the relevant event properties:
const member = [{"memberId":4,"memberName":"ABC","age":22,"eventId":5,"eventName":"Dance"},{"memberId":4,"memberName":"ABC","age":22,"eventId":6,"eventName":"Music"},{"memberId":4,"memberName":"ABC","age":22,"eventId":7,"eventName":"FootBall"},{"memberId":5,"memberName":"PQR","age":24,"eventId":6,"eventName":"Music"},{"memberId":5,"memberName":"PQR","age":24,"eventId":5,"eventName":"Dance"}]
const result = _(member)
.groupBy('memberId')
.map(group => ({
..._.omit(_.head(group), ['eventId', 'eventName']),
events: _.map(group, o => ({ id: o.eventId, name: o.eventName }))
}))
.value();
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
And the same solution using underscore:
const member = [{"memberId":4,"memberName":"ABC","age":22,"eventId":5,"eventName":"Dance"},{"memberId":4,"memberName":"ABC","age":22,"eventId":6,"eventName":"Music"},{"memberId":4,"memberName":"ABC","age":22,"eventId":7,"eventName":"FootBall"},{"memberId":5,"memberName":"PQR","age":24,"eventId":6,"eventName":"Music"},{"memberId":5,"memberName":"PQR","age":24,"eventId":5,"eventName":"Dance"}]
const result = _.chain(member) // <- change for underscore
.groupBy('memberId')
.map(group => ({
..._.omit(_.head(group), ['eventId', 'eventName']),
events: _.map(group, o => ({ id: o.eventId, name: o.eventName }))
}))
.value();
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.9.1/underscore.js"></script>

Categories

Resources