Reputation: 83
I have two arrays authors
and posts
. I want to return the posts arrays with the authors names not their emails, as seen below.
const authors = [
{name: 'Thompson Smith', email: '[email protected]'},
{name: 'John Doe', email: '[email protected]'},
{name: 'Jane Coker', email: '[email protected]'},
{name: 'Mirabel Ekong', email: '[email protected]'},
{name: 'Samuel Doe', email: '[email protected]'},
{name: 'Moses Philips', email: '[email protected]'},
{name: 'Marcus Bowa', email: '[email protected]'},
{name: 'Peter Touch', email: '[email protected]'},
{name: 'Benson Bruce', email: '[email protected]'},
]
const posts = [
{ title: 'title one', authors: ['[email protected]', '[email protected]', '[email protected]'] },
{ title: 'title two', authors: ['[email protected]', '[email protected]', '[email protected]'] },
{ title: 'title three', authors: ['[email protected]', '[email protected]', '[email protected]'] },
{ title: 'title four', authors: ['[email protected]', '[email protected]', '[email protected]'] },
]
I want to return the posts with the actual name of the authors like this
<div>
<h2>{post.title}</h2>
<p>
<span>{post.author.name}</span>
<span>{post.author.name}</span>
<span>{post.author.name}</span>
</p>
</div>
Please how can I achieve this in react/javascript?
EDIT: I forgot to add some really important parts of the question.
In the posts
array, there are some that have the actual names of the authors (not emails) and these names does not occur in the authors array, for example;
{ title: 'title one', authors: ['Michael Johnson', '[email protected]', '[email protected]'] }
In this case, I also want to retrieve the name Michael Johnson
and retrieve the names of the rest of the authors from the authors array.
authors
array, there are extra props that I want to retrieve, such as the userId
and avatar
. In essence the code looks like this; const authors = [
{name: 'Thompson Smith', email: '[email protected]', userId: '001', avatar: '/avatar/1'},
{name: 'John Doe', email: '[email protected]', userId: '002', avatar: '/avatar/2'},
{name: 'Jane Coker', email: '[email protected]', userId: '003', avatar: '/avatar/3'},
{name: 'Mirabel Ekong', email: '[email protected]', userId: '004', avatar: '/avatar/4'},
{name: 'Samuel Doe', email: '[email protected]', userId: '005', avatar: '/avatar/5'},
{name: 'Moses Philips', email: '[email protected]', userId: '006', avatar: '/avatar/6'},
{name: 'Marcus Bowa', email: '[email protected]', userId: '007', avatar: '/avatar/7'},
{name: 'Peter Touch', email: '[email protected]', userId: '008', avatar: '/avatar/8'},
{name: 'Benson Bruce', email: '[email protected]', userId: '009', avatar: '/avatar'}
]
const posts = [
{ title: 'title one', authors: ['[email protected]', '[email protected]', '[email protected]'] },
{ title: 'title two', authors: ['[email protected]', '[email protected]', '[email protected]'] },
{ title: 'title three', authors: ['[email protected]', '[email protected]', '[email protected]'] },
{ title: 'title four', authors: ['[email protected]', '[email protected]', '[email protected]'] },
{ title: 'title five', authors: ['michael Johnson', '[email protected]', '[email protected]'] },
{ title: 'title six', authors: ['michael Johnson', 'Jane Joshua', '[email protected]'] },
]
EXPECTED OUTPUT
<div>
<h2>{post.title}</h2>
<ul>
<li><Link to={userId}><Avatar src={avatar}/>{post.author.name}</Link></li>
<li><Link to={userId}><Avatar src={avatar}/>{post.author.name}</Link></li>
<li><Link to={userId}><Avatar src={avatar}/>{post.author.name}</Link></li>
//If the author does not exist in the authors array, should return
<li><placeHolderAvatar />{post.author.name}</li>
</ul>
</div>
Please how do I retrieve these extra props?
Upvotes: 0
Views: 2381
Reputation: 205
One way is to map the posts
array into another variable.
Inside this map function you could use the Array.filter
and Array.some
methods to return the correct authors like so:
let mappedPosts = posts.map(post => {
post.authors = authors.filter(author => post.authors.some(a => a === author.email));
return post;
});
this would create the same array as your posts
variable except that the authors array is now an array of objects with names and email properties.
By the way: while testing my approach, i noticed your posts
array probably is not seperated correctly:
{ title: 'title one', authors: ['[email protected]', '[email protected], [email protected]'] },
Should be:
{ title: 'title one', authors: ['[email protected]', '[email protected]', '[email protected]'] },
(notice the comma's i placed behind [email protected] and before [email protected].
Edit
In react i would store the new variable in a state, while using the useEffect hook to look for changes in both the authors and posts array using the dependency array:
let [mappedPosts, setMappedPosts] = useState([]);
useEffect(() => {
if (authors && posts) {
setMappedPosts(posts.map(post => {
post.authors = authors.filter(author => post.authors.some(a => a === author.email));
return post;
}));
}
}, [authors, posts]);
basically the same except the React way.
Then you could loop through mappedPosts
and render the authors directly instead of having to filter through a different array inside your JSX which IMO is not very neat.
Edit 2
From what i understand is that you want to check if either the email or the actual name of the author has a match inside the authors array with respect to the posts array.
This is actually quite easy to do, you just have to extend your statement inside the some
function:
let [mappedPosts, setMappedPosts] = useState([]);
useEffect(() => {
if (authors && posts) {
let foundPosts = posts.map(post => {
post.authors = authors.filter(author => {
return post.authors.some(a => {
return a === author.email || a === author.name;
});
});
return post;
});
setMappedPosts(foundPosts);
}
}, [authors, posts]);
If you didn't notice; i've changed up the code a little bit to make it more readable. (store the found posts inside a variable and pass that variable to the setState function instead of alltogether).
Upvotes: 1
Reputation: 8316
First we can build a map
for each email
as key and name
as value and then use the same to get a new posts
array like so :-
const authors = [{
name: 'Thompson Smith',
email: '[email protected]',
userId: '001',
avatar: '/avatar/1'
},
{
name: 'John Doe',
email: '[email protected]',
userId: '002',
avatar: '/avatar/2'
},
{
name: 'Jane Coker',
email: '[email protected]',
userId: '003',
avatar: '/avatar/3'
},
{
name: 'Mirabel Ekong',
email: '[email protected]',
userId: '004',
avatar: '/avatar/4'
},
{
name: 'Samuel Doe',
email: '[email protected]',
userId: '005',
avatar: '/avatar/5'
},
{
name: 'Moses Philips',
email: '[email protected]',
userId: '006',
avatar: '/avatar/6'
},
{
name: 'Marcus Bowa',
email: '[email protected]',
userId: '007',
avatar: '/avatar/7'
},
{
name: 'Peter Touch',
email: '[email protected]',
userId: '008',
avatar: '/avatar/8'
},
{
name: 'Benson Bruce',
email: '[email protected]',
userId: '009',
avatar: '/avatar'
}
]
const posts = [{
title: 'title one',
authors: ['[email protected]', '[email protected]', '[email protected]']
},
{
title: 'title two',
authors: ['[email protected]', '[email protected]', '[email protected]']
},
{
title: 'title three',
authors: ['[email protected]', '[email protected]', '[email protected]']
},
{
title: 'title four',
authors: ['[email protected]', '[email protected]', '[email protected]']
},
{
title: 'title five',
authors: ['michael Johnson', '[email protected]', '[email protected]']
},
{
title: 'title six',
authors: ['michael Johnson', 'Jane Joshua', '[email protected]']
},
]
const nameEmailMap = authors.reduce((acc, {
name,
email,
userId,
avatar
}) => {
acc[email] = {
name,
userId,
avatar
};
return acc;
}, {})
const newPosts = posts.map(({
title,
authors
}) => ({
title,
authors: authors.map(entry => (nameEmailMap[entry] ? { ...nameEmailMap[entry]
} : {
name: entry
}))
}));
console.log(newPosts);
Upvotes: 0
Reputation: 10463
If the need is just to create a new array, then here is a sample that converts the array to the desired outcome
let authors = [
{name: 'Thompson Smith', email: '[email protected]'},
{name: 'John Doe', email: '[email protected]'},
{name: 'Jane Coker', email: '[email protected]'},
{name: 'Mirabel Ekong', email: '[email protected]'},
{name: 'Samuel Doe', email: '[email protected]'},
{name: 'Moses Philips', email: '[email protected]'},
{name: 'Marcus Bowa', email: '[email protected]'},
{name: 'Peter Touch', email: '[email protected]'},
{name: 'Benson Bruce', email: '[email protected]'},
]
let posts = [
{ title: 'title one', authors: ['Michael Johnson', '[email protected]', '[email protected]'] },
{ title: 'title two', authors: ['[email protected]', '[email protected]', '[email protected]'] },
{ title: 'title three', authors: ['[email protected]', '[email protected]', '[email protected]'] },
{ title: 'title four', authors: ['[email protected]', '[email protected]', '[email protected]'] },
]
posts = posts.map(obj => ({ ...obj, authors: obj.authors.map(email => authors.find(auth => auth.email === email)?.name ? authors.find(auth => auth.email === email)?.name : email )}))
console.log(posts)
Upvotes: 0
Reputation: 166
You could have a separate method for filtering out authors and mapping their names like:
function findPostAuthors(post) {
return authors
.filter(({email}) => post.authors.includes(email))
.map(({name}) => name);
}
Also, your posts.authors
arrays, all have two items, you are missing '
between second and third item.
In react you could use it, something like this:
return (
<div className="App">
{posts.map((post) => (
<div>
<h2>{post.title}</h2>
<p>
{findPostAuthors(post)
.map(author => (<span>{author}</span>))}
</p>
</div>
))}
</div>
);
This way you could ditch .map
in findPostAuthors
function, so it wouldn't loop too many times.
Upvotes: 0
Reputation: 25396
This seems like an exercise in javascript map
and filter
.
Here's an example of how you could do it. And a codesandbox: https://codesandbox.io/s/agitated-brown-owf67
Also your email address arrays are formatted weirdly, and since you didn't indicate a reason for that in your question I interpreted it as a typo and fixed them. YMMV.
return (
<div className="App">
{posts.map((p) => (
<div>
<h2>{p.title}</h2>
<p>
{p.authors
.map((a) =>
authors
.filter((author) => author.email === a)
.map((author) => author.name)
)
.map(a => (<span>{a}</span>))}
</p>
</div>
))}
</div>
);
Upvotes: 1