← Projects

Two Dimensional Array Filtering with RegExp

Updated 30 days ago

Another thorny problem. I have an array of categories. Actually they're the transaction categories from Plaid's API. Six hundred and two to be exact.

The problem I was solving for was how to filter the inner array with regex performantly for a search suggest to recategorize transactions.

The data is organized in my app in a two dimensional array shaped like this:

[
   { hierarchy: ["Food and Drink"] },
   { hierarchy: ["Food and Drink", "Restaurants"] },
   { hierarchy: ["Food and Drink", "Restaurants", "Turkish"] },
   ... and so forth
]

Note that the inner array has varying lengths and repeats many of the same strings.

We're going to to use Array.filter and RegExp to hit the array. First we need to get down to the second array.

 const allCats = Categories.find().fetch()
 let results = allCats.filter((category) => {
    let matchSub = category.hierarchy.filter((subCategory) => {
    	return true;
    })
 })

When you return true in Array.filter, it will return the category so thus far we'll return every subCategory. In the second level we need to perform our RegExp.

Now I'm pretty lazy when I'm using applications I make, so I tend to put in a lot of conveniences. I can't be bothered to type the whole category name or use capitalization so let's add the flags "i" to the expression. That makes it match using case insensitive logic. We'll also throw a "^" at the beginning so we match the first part of the subcategory.

 const allCats = Categories.find().fetch()
 let results = allCats.filter((category) => {
   let matchSub = category.hierarchy.filter((subCategory) => {
      const regex = new RegExp('^' + query, 'i')
        return regex.test(subCategory)
      })
   console.log(matchSub)
   return true
 })

Let's see where we're at. This should start sending back matches. If the subCategory matches then it will return an array with that match in it. Otherwise it will be an empty array.

All we need to do is return the matchSub if it's length is greater than 0, otherwise we'll return.

Final solution

 const allCats = Categories.find().fetch()
 let results = allCats.filter((category) => {
   let matchSub = category.hierarchy.filter((subCategory) => {
      const regex = new RegExp('^' + query, 'i')
        return regex.test(subCategory)
      })
   if (matchSub.length > 0) {
     return matchSub
   }
   return
 })