javascriptarraysobjectmatchflatten

Function that takes in a string and a list of books and returns all the books that match the search input


`I've been banging my head against the wall with this and I can't quite figure out where to go from here. I am trying to build a function that takes in a string and a list of books and then returns all the books that match the search input.

It is supposed to take in an array of objects and then filter through them and spit out the matches but I don't know where to go. I'm relatively new to this and get lost easily so any help would be appreciated.

const books = [
{
  title: "The City We Became",
  author: "N. K. Jemisin",
  tags: ["fantasy", "fiction", "afrofutursim", "science fiction", "sci-fi"]
},
{
title: "The Catcher in the Rye",
author: "J. D. Salinger",
tags: ["fiction", "young adult", "YA", "realism", "coming of age", "classic"]
},
{
title: "The Hundred Thousand Kingdoms",
author: "N. K. Jemisin",
tags: ["fantasy", "fiction", "adventure", "series"]
},
{
title: "Sapiens: A Brief History of Humankind",
author: "Yuval Noah Harari",
tags: ["nonfiction", "history", "anthropology", "science", "sociology"]
},
{
title: "Behave: The Biology of Humans at Our Best and Worst",
author: "Robert M. Sapolsky",
tags: ["nonfiction", "anthropology", "science", "sociology", "biology"]
},
{
title: "The Parable of the Talents",
author: "Octavia Butler", 
tags: ["fiction", "dystopian", "science fiction"]
},
{
title: "1984",
author: "George Orwell", 
tags: ["fiction", "dystopian", "science fiction", "classics", "adult"]
},
{
title: "Remarkably Bright Creatures",
author: "Shelby Van Pelt",
tags: ["fiction", "mystery", "magical realism"]
},
{
title: "Crying in H Mart",
author: "Michelle Zauner",
tags: ["memoir", "nonfiction", "autobiography"]
},
{
title: "Wild: From Lost to Found on the Pacific Crest Trail",
author: "Cheryl Strayed",
tags: ["nonfiction", "memoir", "adventure", "travel"]
}
]

// Click handler for search button
const captureSearchValue = () => {
 let input = document.getElementById('search-bar').value;
return input;
};

const filterBooks = (books) => {
  let flattenedObj;
   const flattenedObjsArr = [];
   for (let obj = 0; obj < books.length; obj++) {
    const objValues = Object.values(books[obj]);
    flattenedObj = [objValues.flat()];
    flattenedObjsArr.push(flattenedObj)
   } 
   return flattenedObjsArr;
} 

console.log(filterBooks(books)) //returns all 10 books`

I'm supposed to flatten the object and then return the matches for the search. The example here for a result is a search for 'fantasy' should return 2 results .. but this pulls 10.


Solution

  • If we're searching only the tags, and input tag is given in lowercase, then the search can be stated in a line:

    const filterBooks = tag => books.filter(book => book.tags.includes(tag));
    

    That takes the tag as the parameter which is conventional. It might also take the array as param like this...

    const filterBooks = (books, tag) => books.filter(book => book.tags.includes(tag));
    

    If the only param is an array, we'll need a way to get the tag from within the function, something like this...

    const filterBooks = books => {
      const tag = // get the searched tag from the UI somehow
      return books.filter(book => book.tags.includes(tag));
    }
    

    If there's a more complex search, like matching the author or other fields, you could factor the predicate, too, as follows...

    const filterBooks = books => {
      const term = // get the searched tag from the UI somehow
      cost predicate = book => {
        return book.tags.includes(term) ||
               book.author.includes(term) // || etc
      }
      return books.filter(predicate);
    }
    

    Finally, as another user suggested, if case insensitivity is needed, convert the thing being searched and the values being searched into the same case.

    Here's the simplest idea demo'd...

    const books = [{
        title: "The City We Became",
        author: "N. K. Jemisin",
        tags: ["fantasy", "fiction", "afrofutursim", "science fiction", "sci-fi"]
      },
      {
        title: "The Catcher in the Rye",
        author: "J. D. Salinger",
        tags: ["fiction", "young adult", "YA", "realism", "coming of age", "classic"]
      },
      {
        title: "The Hundred Thousand Kingdoms",
        author: "N. K. Jemisin",
        tags: ["fantasy", "fiction", "adventure", "series"]
      },
      {
        title: "Sapiens: A Brief History of Humankind",
        author: "Yuval Noah Harari",
        tags: ["nonfiction", "history", "anthropology", "science", "sociology"]
      },
      {
        title: "Behave: The Biology of Humans at Our Best and Worst",
        author: "Robert M. Sapolsky",
        tags: ["nonfiction", "anthropology", "science", "sociology", "biology"]
      },
      {
        title: "The Parable of the Talents",
        author: "Octavia Butler",
        tags: ["fiction", "dystopian", "science fiction"]
      },
      {
        title: "1984",
        author: "George Orwell",
        tags: ["fiction", "dystopian", "science fiction", "classics", "adult"]
      },
      {
        title: "Remarkably Bright Creatures",
        author: "Shelby Van Pelt",
        tags: ["fiction", "mystery", "magical realism"]
      },
      {
        title: "Crying in H Mart",
        author: "Michelle Zauner",
        tags: ["memoir", "nonfiction", "autobiography"]
      },
      {
        title: "Wild: From Lost to Found on the Pacific Crest Trail",
        author: "Cheryl Strayed",
        tags: ["nonfiction", "memoir", "adventure", "travel"]
      }
    ];
    
    const filterBooks = tag => books.filter(book => book.tags.includes(tag));
    
    console.log(filterBooks("fantasy"));