0

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.

  1. 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.

  1. In the authors array, there are extra props that I want to retrieve, such as the userIdand 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?

2
  • After updating your requirements, can you also add the expected output now ? Commented Jul 10, 2021 at 4:11
  • @LakshyaThakur I now added the expected output. Thanks in anticipation Commented Jul 10, 2021 at 6:03

5 Answers 5

1

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>
  );
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you so much. This works exactly as I want, but there are some important parts of the question which I forgot to mention in the initial post, such as retrieving extra props in the authors array. I have now added more details in the original post. Can you please help?
I have updated the original question with more details. I'll really appreciate your help
1

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).

3 Comments

This seems like what I want to do, but the posts return with an empty array of authors. I don't know why. I edited my original post and added a detail explanation. Perhaps you could help
I have updated the original question with more details. I'll really appreciate your help
Added a possible solution to your new question underneath "edit 2"
0

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);

3 Comments

This works exactly as I want, but there are some important parts of the question which I forgot to mention in the initial post, such as retrieving extra props in the authors array. I have now added more details in the original post. Can you please help with it? Thanks so much
I have updated the original question with more details. I'll really appreciate your help
Exactly what I wanted. Thank you so much Sir.
0

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.

2 Comments

Thank you so much. This works exactly as I want, but there are some important parts of the question which I forgot to mention in the initial post, such as retrieving extra props in the authors array. I have now added more details in the original post. Can you me please help?
I have updated the original question with more details. I'll really appreciate your help
0

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)

3 Comments

This works exactly as I want, but there are some important parts of the question which I forgot to mention in the initial post, such as retrieving extra props in the authors array. I have now added more details in the original post. Can you please help with it?
@BigBros I updated my answer but i didnt udnerstand the second part. how is the desired output of posts with these new props that you want? please give us an example
Thanks very much. I now updated the original question to include the desired output. Thanks in anticipation

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.