[SOLVED] How can I refactor this function call that seems to repeat alot of the same thing over over again?

Issue

I have made function to search through blog posts. However, I have to make sure that titles take precedence over excerpt and excerpt over content when added to the containsQuery array. I have made the following code, it seems to be functioning well but seems there are a lot redundant code. How can I improve this?

const findArticles = (posts: any[], query: string) => {
    const containsQuery: any[] = []
    let words
    let i: number

    if (query.includes(' ')) {
      words = query.toLowerCase().split(' ')
    }

    const findArticle = (multipleWords:boolean, posts: any[], query:string, searchedParam:string, words:string[] = [],) => {
      if (multipleWords === false) {
        for (i = 0; i < posts.length; i++) {
          if (posts[i][`${searchedParam}`].toLowerCase().includes(query.toLowerCase())) {
            containsQuery.push(posts[i])
          }
        }
      } else {
        for (i = 0; i < posts.length; i++) {
          if(words.every(q => posts[i][`${searchedParam}`].toLowerCase().includes(q))) {
            containsQuery.push(posts[i])
          }
        }
      }
     
    }

    if (words) {
      findArticle(true,  posts, query, 'title', words,)
     } else {
      findArticle(false, posts, query, 'title')
     }

     if (words) {
      findArticle(true,  posts, query, 'excerpt', words,)
     } else {
      findArticle(false, posts, query, 'excerpt')
     }

     if (words) {
      findArticle(true,  posts, query, 'content', words,)
     } else {
      findArticle(false, posts, query, 'content')
     }

    const oneOfKind = Array.from(new Set(containsQuery.map(article => article.id))).map(id => {
      return containsQuery.find(a => a.id === id)
    })
    
    return oneOfKind
  }

In order to avoid duplicates and save time, I tried to copy the posts in to my own const copyOfPosts = posts and then mutate it as below. But this ended up breaking the code for some reason. Above code seems to be the only way I can make it work right. Any suggestion is most welcome.

if (posts[i][`${searchedParam}`].toLowerCase().includes(query.toLowerCase())) {
            containsQuery.push(posts[i])
            copyOfPosts.splice(i, 1)
          }

Solution

Here:

const findArticle = (multipleWords:boolean, posts: any[], query:string, searchedParam:string, words:string[]) => {
    const containsQuery: any[] = []
    if (multipleWords === false) {
        for (let i = 0; i < posts.length; i++) {
            if (posts[i][`${searchedParam}`].toLowerCase().includes(query.toLowerCase())) {
                containsQuery.push(posts[i])
            }
        }
    } else {
        for (let i = 0; i < posts.length; i++) {
            if(words.every(q => posts[i][`${searchedParam}`].toLowerCase().includes(q))) {
                containsQuery.push(posts[i])
            }
        }
    }
    return containsQuery
}

const findArticles = (posts: any[], query: string) => {

    let words = query.includes(' ') ? query.toLocaleLowerCase().split(' ') : [] 

    const containsQuery = findArticle(true, posts, query, 'title', words)

    containsQuery.push(...findArticle(true, posts, query, 'excerpt', words))

    containsQuery.push(...findArticle(true, posts, query, 'content', words))

    const oneOfKind = Array.from(new Set(containsQuery.map(article => article.id))).map(id => {
        return containsQuery.find(a => a.id === id)
    })
    
    return oneOfKind
}

I would refactor findArticle in a better way for me

const findArticle = (multipleWords:boolean, posts: any[], query:string, searchedParam:string, words:string[]) => {
    const containsQuery: any[] = []
    if (multipleWords === false) {
        for (let i = 0; i < posts.length; i++) {
            if (posts[i][`${searchedParam}`].toLowerCase().includes(query.toLowerCase())) {
                containsQuery.push(posts[i])
            }
        }

        return containsQuery
    } 
    
    for (let i = 0; i < posts.length; i++) {
        if(words.every(q => posts[i][`${searchedParam}`].toLowerCase().includes(q))) {
            containsQuery.push(posts[i])
        }
    }
    return containsQuery
}

This is because I do not like use an excessive else like in this case, but people could complain about using two return.

Answered By – Nullable

Answer Checked By – Candace Johnson (BugsFixing Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *