Filter an array of objects based on multiple search terms

Viewed 132

Say I have a search term, const searchTerms = ['sarasota', 'fl']

And a list of locations,

const selectedRestaurants = [{
  city: "Orlando",
  name: "Dons Food Place",
  state: "FL",
  id: 1
},
{
  city: "Sarasota",
  name: "Rons World",
  state: "FL",
  id: 2
}]

If I search 'Sarasota FL', I want to only return the one Sarasota FL location. But if I'm searching based on multiple parameters (City and State) the search returns both locations, because it matches the state during my second iteration. EDIT: I also need this to work when I search only 'Sarasota'

Here is my code:

filterBySearchTerm(searchTerms) {
   let searchedRestaurants = [];

      for (var j = 0; j < selectedRestaurants.length; j++) {
        searchTerms.forEach(term => {
          if (term.toLowerCase() === this.state.selectedRestaurants[j].city.toLowerCase()) {
            searchedRestaurants.push(this.state.selectedRestaurants[j])
          }
          if (term.toLowerCase() === this.state.selectedRestaurants[j].state.toLowerCase()) {
            searchedRestaurants.push(this.state.selectedRestaurants[j])
          }
          if (term.toLowerCase() === this.state.selectedRestaurants[j].name.toLowerCase()) {
            searchedRestaurants.push(this.state.selectedRestaurants[j])
          }
        })
      }

      //I use Set to remove duplicates ^^
      searchedRestaurants = [...new Set(searchedRestaurants)]
      
      return searchedRestaurants;
  }

I've been stuck on this for a bit now...can anyone help? Might not make a difference but I'm in ReactJS.

3 Answers

const selectedRestaurants = [
  {
    city: "Orlando",
    name: "Dons Food Place",
    state: "FL",
    id: 1,
  },
  {
    city: "Sarasota",
    name: "Rons World",
    state: "FL",
    id: 2,
  },
  {
    city: "Sarasota",
    name: "Rons World",
    state: "SL",
    id: 3,
  },
];

function search(searchTerms) {
  let isCity = !!selectedRestaurants.filter((i) =>
    searchTerms.includes(i.city.toLowerCase())
  ).length;

  let isState = !!selectedRestaurants.filter((i) =>
    searchTerms.includes(i.state.toLowerCase())
  ).length;

  return selectedRestaurants.filter((r) => {
    if (isCity && isState) {
      return (
        searchTerms.includes(r.city.toLowerCase()) &&
        searchTerms.includes(r.state.toLowerCase())
      );
    } else {
      return searchTerms.includes(r.city.toLowerCase());
    }
  });

}

// All city match with sarasota
console.log(search( ["sarasota"]));

// All city match with sarasota and state f1
console.log(search( ["sarasota", "fl"]));

const restaurants = [
  {
    city: 'Orlando',
    name: 'Dons Food Place',
    state: 'FL',
    id: 1,
  },
  {
    city: 'Sarasota',
    name: 'Rons World',
    state: 'FL',
    id: 2,
  },
];
const searchTerms = ['sarasota', 'fl'];
const lowerCasedTerms = searchTerms.map((term) => term.toLowerCase());
const params = ['city', 'state'];

const result = restaurants.filter((restaurant) =>
  lowerCasedTerms.every((lowerCasedTerm) =>
    params.some((param) => restaurant[param].toLowerCase().includes(lowerCasedTerm)),
  ),
);

console.log(result);

What do you think about this approach? It's merging all object values to check if all search terms are included inside it.

const selectedRestaurants = [
  {
    city: "Orlando",
    name: "Dons Food Place",
    state: "FL",
    id: 1
  },
  {
    city: "Sarasota",
    name: "Rons World",
    state: "FL",
    id: 2
  }
];

const searchTerms = ['sarasota', 'fl'];

const foundRestaurants = selectedRestaurants.filter((restaurant) => {
  const valuesAsString = Object.values(restaurant).join(' ').toLowerCase();
  const allTermsMatching = searchTerms
    .map(term => valuesAsString.includes(term.toLowerCase()))
    .every(match => !!match);
  return allTermsMatching;
});

console.log(foundRestaurants);

Related