3

I am trying to filter duplicates from two arrays...

responseData.posts and fbFormattedPosts are both arrays of post objects. Some posts appear in both arrays with the same 'postId'. I'd like to set my state to an array containing all posts of responseData.posts... then I want to add the fbFormattedPosts to that array - But I don't want to include the fbFormattedPosts that have the same 'postId'.

I set my 'posts' useState array using the useState function setPosts. If I use the spread operator for them, they both add all the posts from each array. This works, but I end up with duplicate posts.

//set All Posts
        setPosts([ ...responseData.posts, ...fbFormattedPosts])

So, I am trying to compare the Ids to filter them out.

setPosts([ ...responseData.posts, fbFormattedPosts.forEach(fbPost => {
            responseData.posts.filter(resPost => {
                if(fbPost.postId !== resPost.postId ){
                    return fbPost
                }
            })
        })])

Obviously this doesn't work... Now I get no posts at all. Not even the responseData.posts.

Yevhen Horbunkov
  • 14,965
  • 3
  • 20
  • 42
Nick McLean
  • 601
  • 1
  • 9
  • 23

3 Answers3

1

Following your logic, fbFormattedPosts should be filtered based on postId missing from responseData.posts, so what you need is simply look up for matches (e.g. using some methods, like Array.prototype.find() or Array.prototype.some(), that will be evaluated truthy and exit immediately upon match) inside Array.prototype.filter() and don't forget to spread the result of filter (using ...):

setPosts([ 
   ...responseData.posts, 
   ...fbFormattedPosts
      .filter(fbPost => 
         !responseData.posts
            .find(post => 
               post.postId == fbPost.postId
            )
      )
])
Yevhen Horbunkov
  • 14,965
  • 3
  • 20
  • 42
  • This one works! I'll have time to sit down later and figure out why this works... – Nick McLean May 10 '20 at 19:43
  • I get lost past the parameter of the .filter() - It looks like you are destructuring the postId... then how does !responseData.posts.find()... work? – Nick McLean May 10 '20 at 19:50
  • @NickMcLean : I'm destructuring `postId` within the scope of `filter()` callback, so it is equivalent to having variable equal to current `postId` of given item of `fbFormattedPosts` while comparing it (within the same scope) with `post.postId` of `responseData.posts`. – Yevhen Horbunkov May 10 '20 at 20:09
  • @NickMcLean : I've removed destructuing to eliminate the source of confusion, It should still work ;) – Yevhen Horbunkov May 10 '20 at 20:28
  • Thanks so much for your help and explanation. I think I am starting to understand this one! I have only ever done .filter() with an array comparing to a single value. Dang this one is so cool - thanks again! – Nick McLean May 10 '20 at 23:56
0

Your main idea is right but you doesn't do it in a right way. You need to filter your fbFormattedPosts before adding. Array.every tests whether all elements in the array pass the test implemented by the provided function. Array.filter cut all elements for which every return false

setPosts([ ...responseData.posts, fbFormattedPosts.filter(fbPost => {
        return responseData.posts.every(resPost => {
            return fbPost.postId !== resPost.postId
        })
    })])
0

If you want to spread the arrray in a functional way you should use Array filter and some:

setPosts([ ...responseData.posts, ...fbFormattedPosts.filter(fbPost => (
            !responseData.posts.some(resPost =>
                fbPost.postId === resPost.postId 
            )
        ))])
maioman
  • 18,154
  • 4
  • 36
  • 42