Home > OS >  Better search from beginning string inside array of objects
Better search from beginning string inside array of objects

Time:09-10

I have like this addresses list:

const addresses = [
  {
    id: 1,
    address: "St. East Baltimore, 820",
    district: [
      {
        id: 1,
        title: "Mfume"
      }
    ]
  },
  {
    id: 2,
    address: "St. Darnestown Rd, 12187",
    district: [
      {
        id: 7,
        title: "Trone"
      }
    ]
  },
  {
    id: 3,
    address: "St. Elm Street",
    district: [
      {
        id: 4,
        title: "Raskin Sarbanes"
      }
    ]
  },
  {
    id: 4,
    address: "St. Bethesda Ave",
    district: [
      {
        id: 12,
        title: "Rayburn House"
      }
    ]
  },
  {
    id: 5,
    address: "St. Bethesda Lane, 7111",
    district: [
      {
        id: 2,
        title: "Connolly"
      }
    ]
  },
  {
    id: 6,
    address: "St. Trolls Toys, 643",
    district: [
      {
        id: 8,
        title: "Beyer"
      }
    ]
  },
  {
    id: 7,
    address: "St. Houlton, 12",
    district: [
      {
        id: 45,
        title: "Lee Zeldin House"
      }
    ]
  },
];

I need to search string by address and by district. I do it like this:

const searchQuery = "Be"
const regex = new RegExp('^'   searchQuery, 'i');

const searchByAddress = addresses.filter((addr) => {
  return addr.address.replace("St. ", '').trim().search(regex) == 0;
});
const searchByDistrict = addresses.filter((addr) => {
  return addr.district[0].title.search(regex) == 0;
});

var result = []

result.push(searchByAddress)
searchByDistrict.map(item => {
  const found = result.some(el => el.id === item.id);
  if(!found) {
    result.push(item);
  }
})

console.log("Result: ", result)

Maybe anyone have better idea to search and get needed objects in my case? In my case it's work slow. Maybe this code can be performed?

Here is the demo of my solution:

const addresses = [{
    id: 1,
    address: "St. East Baltimore, 820",
    district: [{
      id: 1,
      title: "Mfume"
    }]
  },
  {
    id: 2,
    address: "St. Darnestown Rd, 12187",
    district: [{
      id: 7,
      title: "Trone"
    }]
  },
  {
    id: 3,
    address: "St. Elm Street",
    district: [{
      id: 4,
      title: "Raskin Sarbanes"
    }]
  },
  {
    id: 4,
    address: "St. Bethesda Ave",
    district: [{
      id: 12,
      title: "Rayburn House"
    }]
  },
  {
    id: 5,
    address: "St. Bethesda Lane, 7111",
    district: [{
      id: 2,
      title: "Connolly"
    }]
  },
  {
    id: 6,
    address: "St. Trolls Toys, 643",
    district: [{
      id: 8,
      title: "Beyer"
    }]
  },
  {
    id: 7,
    address: "St. Houlton, 12",
    district: [{
      id: 45,
      title: "Lee Zeldin House"
    }]
  },
];
const searchQuery = "Be"
const regex = new RegExp('^'   searchQuery, 'i');

const searchByAddress = addresses.filter((addr) => {
  return addr.address.replace("St. ", '').trim().search(regex) == 0;
});
const searchByDistrict = addresses.filter((addr) => {
  return addr.district[0].title.search(regex) == 0;
});

var result = []

result.push(searchByAddress)
searchByDistrict.map(item => {
  const found = result.some(el => el.id === item.id);
  if (!found) {
    result.push(item);
  }
})

console.log(result);

CodePudding user response:

The following snippet will take care of all elements of a district array. The actual rx-test will be carried out only once per element:

const addresses = [
  {id: 1,address: "St. East Baltimore, 820",district: [{id: 1,title: "Mfume"}]},
  {id: 2,address: "St. Darnestown Rd, 12187",district: [{id: 7,title: "Trone"},
                                   {id: 8,title:"Beatles"}]}, // added for testing!
  {id: 3,address: "St. Elm Street",district: [{id: 4,title: "Raskin Sarbanes"}]},
  {id: 4,address: "St. Bethesda Ave",district: [{id: 12,title: "Rayburn House"}]},
  {id: 5,address: "St. Bethesda Lane, 7111",district: [{id: 2,title: "Connolly"}]},
  {id: 6,address: "St. Trolls Toys, 643",district: [{id: 8,title: "Beyer"}]},
  {id: 7,address: "St. Houlton, 12",district: [{id: 45,title: "Lee Zeldin House"}]},
];

const srch="Be", rx = new RegExp("^" srch,"im"); // flags: case insensitive, multiline 
let res = addresses.map(itm =>[  (rx.test(itm.address.replace(/^ *St. */, ''))?1:0)  // test result flag: 1 for address, 2 for title  
                              || (rx.test(itm.district.map(d=>d.title).join("\n"))?2:0), itm] )
                   .filter(([k,v])=>k)      // only matched results
                   .sort((a,b)=>a[0]-b[0])  // sort results according to rx test result flag ...
                   .map(([k,v])=>v);        // remove the result flag again 
                              
console.log(res);

After realizing that the order of test results was significant I changed my script. Now it will deliver the address matches first, followed by the title matches (of all possible districts).

The computationally expensive pattern matching will be carried out once per element only. This should make it reasonably fast. Even though there are further .filter(), .sort() and .map() steps involved, these are fairly trivial and don't require much computation.

CodePudding user response:

If you are always going to compare district[0], you can simplify your code to:

const addresses = [{
    id: 1,
    address: "St. East Baltimore, 820",
    district: [{
      id: 1,
      title: "Mfume"
    }]
  },
  {
    id: 2,
    address: "St. Darnestown Rd, 12187",
    district: [{
      id: 7,
      title: "Trone"
    }]
  },
  {
    id: 3,
    address: "St. Elm Street",
    district: [{
      id: 4,
      title: "Raskin Sarbanes"
    }]
  },
  {
    id: 4,
    address: "St. Bethesda Ave",
    district: [{
      id: 12,
      title: "Rayburn House"
    }]
  },
  {
    id: 5,
    address: "St. Bethesda Lane, 7111",
    district: [{
      id: 2,
      title: "Connolly"
    }]
  },
  {
    id: 6,
    address: "St. Trolls Toys, 643",
    district: [{
      id: 8,
      title: "Beyer"
    }]
  },
  {
    id: 7,
    address: "St. Houlton, 12",
    district: [{
      id: 45,
      title: "Lee Zeldin House"
    }]
  },
];

const searchQuery = "Be"
const regex = new RegExp('^'   searchQuery, 'i');

let result = addresses.filter(item => {
  return item.address.replace("St. ", '').trim().search(regex) == 0 || item.district[0].title.search(regex) == 0;
});

console.log(result);

  • Related