1

I am trying to create a function that can be used in a variety of use cases for finding a value in a list (array). Here is the code I have:

function findInArray(needle, arr, exact, sensitive) {
  if (needle && arr) {
    var hayLength = arr.length
    for (var i = 0; i < hayLength; i++) {
      if (arr[0].length >= 0) {var haystack = arr[i][0];}
      else {haystack = arr[i];}
      if (exact && sensitive && (haystack === needle)) {return i;}
      else if (exact && !(sensitive) && (haystack == needle)) {return i;}
      else if (!(exact) && sensitive && (haystack.toLowerCase().search(needle.toLowerCase()))>-1) {return i;}
      else if (!(exact) && !(sensitive) && haystack.search(needle)>-1) {return i;}
    }
  }
  return -1;
}

I am sure the above code can be optimized, but I am not getting the third case to work when I want to match a string in a list ignoring case. E.g.

var arr = ["Partner1", "Partner2"]
var needle = "partner1"
var n = findInArray(needle, arr, true, false);

Returns -1.

I want the function to work with a 1D list, or multidimensional list, as well as find substrings (e.g. match "Google" and "Googler").

Answered: Combining @NoobishPro and @tehhowch "best of", this works well:

function findInArray(needle, arr, exact, sensitive) {
  exact = exact !== false;
  sensitive = sensitive !== false;

  //We will catch the sensitivity parameter here to save performance
  if (!sensitive) {
    needle = needle.toLowerCase();
  }

  //determine array length
  var hayLength = arr.length;
  for (var i = 0; i < hayLength; i++) {
    //Set haystack
    var haystack = arr[i];
    //Check if it's another array. If so, redo this function to go 1 level deeper.
    if (haystack.constructor == Array) {
      return findInArray(needle, haystack, exact, sensitive);
    }

    //We can lowercase it here to save on if-statement lowercasing
    if (!sensitive) {
      haystack = haystack.toLowerCase();
    }

    //easy one
    if (exact && sensitive && (haystack == needle)) {
      return i;
    } else if (exact & (haystack == needle)) {
      return i;
    } else if (!exact & (haystack.search(needle)) > -1) {
      return i;
    }
  }
  return -1;
}
Steve Gon
  • 347
  • 6
  • 18

2 Answers2

2

WORKING JSFIDDLE

It's because your recursion attempt was all weird. Most of your code was pretty decent. You also forgot 1 toLowerCase().

This should work;

var arr = ["Partner1", "Partner2"]
var needle = "partner1"
var n = findInArray(needle, arr, true, false);
console.log(n);

function findInArray(needle, arr, exact, sensitive) {
  //Check if these attributes were even given
  if (typeof needle != 'undefined' && typeof arr != 'undefined') {
    if (arr.length < 1) {
      return -1;
    }
    if (typeof exact == 'undefined') {
      //Also making sure it's always set. Defaults to false.
      exact = false;
    }
    if (sensitive == 'undefined') {
      //Also making sure it's always set. Defaults to false.
      sensitive = false;
    }
    //determine array length
    var hayLength = arr.length;
    for (var i = 0; i < hayLength; i++) {
      //Set haystack
      var haystack = arr[i];
      //Check if it's another array. If so, redo this function to go 1 level deeper.
      if (haystack.constructor == Array) {
        return findInArray(needle, haystack, exact, sensitive);
      }

      //You got this quite right. Missed a toLowerCase on the last one.
      if (exact && sensitive && (haystack === needle)) {
        return i;
      } else if (exact && !(sensitive) && (haystack.toLowerCase() == needle.toLowerCase())) {
        return i;
      } else if (!(exact) && sensitive && (haystack.search(needle)) > -1) {
        return i;
      } else if (!(exact) && !(sensitive) && haystack.toLowerCase().search(needle.toLowerCase()) > -1) {
        return i;
      }
    }
  }
  return -1;
}

A few tiny optimisations

I also took the time to do a little optimisation for your code. JSFIDDLE

var arr = ["Partner1", "Partner2"]
var needle = "partner2"
var n = findInArray(needle, arr, true, false);
console.log(n);

function findInArray(needle, arr, exact, sensitive) {
  //Check if these attributes were even given
  if (typeof needle != 'undefined' && typeof arr != 'undefined') {
    if (arr.length < 1) {
      return -1;
    }
    if (typeof exact == 'undefined') {
      //Also making sure it's always set. Defaults to false.
      exact = false;
    }
    if (sensitive == 'undefined') {
      //Also making sure it's always set. Defaults to false.
      sensitive = false;
    }

    //We will catch the sensitivity parameter here to save performance
    if (!sensitive) {
      needle = needle.toLowerCase();
    }

    //determine array length
    var hayLength = arr.length;
    for (var i = 0; i < hayLength; i++) {
      //Set haystack
      var haystack = arr[i];
      //Check if it's another array. If so, redo this function to go 1 level deeper.
      if (haystack.constructor == Array) {
        return findInArray(needle, haystack, exact, sensitive);
      }

      //We can lowercase it here to save on if-statement lowercasing
      if (!sensitive) {
        haystack = haystack.toLowerCase();
      }

      //easy one
      if (exact && sensitive && (haystack == needle)) {
        return i;
      } else if (exact & (haystack == needle)) {
        return i;
      } else if (!exact & (haystack.search(needle)) > -1) {
        return i;
      }
    }
  }
  return -1;
}
NoobishPro
  • 2,539
  • 1
  • 12
  • 23
  • 1
    For coercing optionals to a default `true` boolean, I like `arg = arg !== false;` – tehhowch Jun 07 '18 at 02:01
  • 1
    @tehhowch that sounds like something that could clean up some of my classes very neatly, thanks for the tip! I honestly didn't know it existed! Do you know where I can get a little bit more information on that syntactic sugar of yours? – NoobishPro Jun 07 '18 at 02:03
  • 1
    It's just plain JS, but may have unexpected results if your calling code thinks it can pass `0`, `""`, `null`, etc. instead of `false` to activate the same behavior, because 0 is not strictly equal to false, so then `arg` will be cast to the boolean `true`. – tehhowch Jun 07 '18 at 02:10
  • 1
    @tehhowch ah, sounds like a good reason not to use it, then. I'd rather keep stable similar code than to make an exception for only 1 specific type. Did you know this one? I found it to be very confusing as well; `arr = arr || []` if only I knew what to call these shorthands so I could google them... – NoobishPro Jun 07 '18 at 02:14
  • 1
    Double-pipe is a short-circuit operator. If `arr` is truthy, `arr` stays as what it is. Otherwise, it becomes an empty array. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_Operators As far as my original comment, if you drop the strict equality (`!== -> !=`) then arg (=0) = (0 != false) is arg = (false != false) -> arg = (false) -> arg = false. See also https://stackoverflow.com/questions/31155477/cleanest-way-to-convert-to-boolean – tehhowch Jun 07 '18 at 02:16
  • 1
    ahh thanks! Thanks to you I've just found this extremely informative page; https://www.sitepoint.com/shorthand-javascript-techniques/ – NoobishPro Jun 07 '18 at 02:20
  • Thanks @NoobishPro and @tehhowch! I combined both your answers and it works great. – Steve Gon Jun 07 '18 at 02:49
0

You can use builtin Array.prototype.find or Array.prototype.indexOf

var arr = ["Partner1", "Partner2"];
var needle = "partner1";
var n = findInArray(needle, arr, true, false);
console.log(n);
function findInArray (input, array, exact, caseSenstive) {
   if (caseSenstive) {
      input = input.toLowerCase();
   }
   if (!exact){
      return array.find(i => i.toLowerCase().indexOf(input)) || -1;
   }
   if (caseSenstive) {
      return array.find(i => i === input) || -1;
   }
   return array.find(i => i.toLowerCase() === input) || -1;
}
Zohaib Ijaz
  • 21,926
  • 7
  • 38
  • 60