Markstar
Markstar

Reputation: 873

Search for string or number in a string or number

I'm trying to implement a search of an object with multiple key/value pairs that can be either string or number.

This is what I'm currently using (simplified, of course):

const input = 'Hello WORld 21';   // this could also be of type number
const search = 'O w';   // this could also be of type number
let result = true;
let startTime, endTime;
const t0 = performance.now();
for (let i = 0; i < 1000000; i++) {
    let parsedInput = JSON.stringify(input).toLowerCase().replace(/(^"|"$)/g, '');
    let parsedSearch = JSON.stringify(search).toLowerCase().replace(/(^"|"$)/g, '');
    result = parsedInput.indexOf(parsedSearch);
}
const t1 = performance.now();
console.log(`Call to doSomething took ${t1 - t0} milliseconds with result = ${result}`);
// ~393ms on a Ryzen 5600X

So this works, but seems to be expensive, especially when I go through tens of thousands of objects (or even more). So I wonder if there is a more elegant way to implement a search like this.

Thank you in advance!

Edit: Based on Sergio J's answer, here is what I got now:

const t2 = performance.now();
let i, s;
for (let j = 0; j < 1000000; j++) {
    i = isNaN(input) ? input.toLowerCase() : input.toString().toLowerCase();
    s = isNaN(search) ? search.toLowerCase() : search.toString().toLowerCase();
    result = i.indexOf(s);
}
const t3 = performance.now();
console.log(`Call to doSomething took ${t3 - t2} milliseconds with result = ${result}`);
// ~66ms on a Ryzen 5600X

Upvotes: 1

Views: 533

Answers (1)

Sergio J
Sergio J

Reputation: 61

you may not need that Json.stringify, just toString() in the cases where the input is a number (check with isNaN()).

There are some post here talking about the efficiency of different methods.

JavaScript: indexOf vs. Match when Searching Strings? check the link to find the most suitable for your needs and users.

Here is a code snippet with a indexOf version, extracted in a function, that checks input and search values to convert them to string if necessary, and tells you what has been found.

function stringFinderIndexOf(input, search) {
  let isNumber = !isNaN(input);
  if (isNumber) {
    input = input.toString();
  }

  let isSearchANumber = !isNaN(search);
  if (isSearchANumber) {
    search = search.toString();
  }

  let foundElement = input.toLowerCase().indexOf(search.toLowerCase()) !== -1;

  if (foundElement) {
    let isNumberText = isNumber ? "a numeric value" : "a text";
    console.log("found with indexOf in " + isNumberText);
  }
}

Of course, if you have as I understand an object, and you want to loop through, you could use Object.values() and a for loop.

function stringInObjectFinder(input, search) {

  let values = Object.values(input)
  for (const key in values) {
    stringFinderIndexOf(key, search);
  }

}

Find full code in a sandbox with a couple of functions using other methods as string.match(regex).

https://codesandbox.io/s/focused-chatterjee-gqijlr?file=/src/index.js

-------- Addition --------

Edit: as author suggested cleaner if, it is always a good idea to extract the if as a method with an explanatory name. In this case was left in order to put all code in a function to explain myself.

You can see in the function duplicated code already (smells).

function transformToStringIfNecessary(input) {
  let isInputANumber = !isNaN(input);
  if (isInputANumber) {
    input = input.toString();
  }
  return input;
}

function containsInputTheSearchValue(input, search) {
  return input.toLowerCase().indexOf(search.toLowerCase()) !== -1;
}

function stringFinderIndexOf(input, search) {
  let isNumber = !isNaN(input);
  input = transformToStringIfNecessary(input);
  search = transformToStringIfNecessary(search);
  let parsedInput = containsInputTheSearchValue(input, search);
  if (parsedInput) {
    let isNumberText = isNumber ? "a numeric value" : "a text";
    console.log("found with indexOf in " + isNumberText);
  }
}

You could clean the code even more, but guess you got the point. Hope it helps.

Upvotes: 3

Related Questions