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)
}
CodePudding user response:
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
.