3

Okay, so this is something i partially have working (ignoring case sensitivity) comparing the following:

arrayA = ["apples", "Oranges", "salt", "Cracked Black Pepper"];
arrayB = ["salt", "pepper", "orange"]

which works 'partially' with the following:

findAnyMatch(arrayA, arrayB): string[] {
    let returnArray = [];
    let conditionedArrayA = arrayA.map(i => i.toLowerCase().trim())
    for (let i = 0; i < arrayB.length; i++) {
      if (conditionedArrayA .includes(arrayB[i].toLowerCase().trim())) {
        ret.push(arrayB[i].toLowerCase().trim());
      }
    }
    return returnArray;
  }

Which returns: "salt", "orange" quite happily; the problem being that it can't see "pepper" in arrayA because it has "cracked black" in front of it.

How do i get it to search anywhere inside each string of the conditioned arrayA?

Thanks

Logan
  • 806
  • 8
  • 17
  • The title of your question and the problem description in your body are at odds. "Cracked Black Pepper" is not a substring of "pepper", but ignoring case sensitivity, "pepper" is a substring of "Cracked Black Pepper". Was your question intended to be "filter two arrays where array B contains any substring of A"? – Patrick Roberts Mar 14 '19 at 17:18
  • Good point, changed it – Logan Mar 14 '19 at 17:24

2 Answers2

4

You can use filter and some. with regex

  • Filter is used to get desired values only.
  • Some is used to check if any of values in arrayA matches with current element.
  • Regex is used to match the string. i flag is used for case insensitivity.

let arrayA = ["apples", "Oranges", "salt", "Cracked Black Pepper"];
let arrayB = ["salt", "pepper", "orange"]

let find = (A,B) => {
  return B.filter(b=> A.some(a=> new RegExp(b,'i').test(a)))
}

console.log(find(arrayA,arrayB))
Code Maniac
  • 37,143
  • 5
  • 39
  • 60
  • Just a side note, make sure that your arrays aren't strings that come from user input in any way. If they are, use [this](https://stackoverflow.com/a/3561711/1541563) for escaping the strings before passing them to the [`RegExp`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp) constructor or you'll end up with a vulnerability. – Patrick Roberts Mar 14 '19 at 21:45
1

Since arrayB contains the "needles", and arrayA contains the "haystacks", so to speak, you can use String.prototype.includes(). Note you are actually using Array.prototype.includes() in your attempt, which is why it only matches "salt" (based on your example code, I am highly doubtful that even "orange" was a successful match).

Below is a solution that uses String.prototype.includes() instead:

function matchedSubstrings (haystacks, needles) {
  return needles.filter(function (needle) {
    const lowerCaseNeedle = needle.toLowerCase()
    return this.some(haystack => haystack.includes(lowerCaseNeedle))
  }, haystacks.map(haystack => haystack.toLowerCase()))
}

const arrayA = ["apples", "Oranges", "salt", "Cracked Black Pepper"]
const arrayB = ["Salt", "pepper", "orange"]

console.log(matchedSubstrings(arrayA, arrayB))

The this of the Array.prototype.filter() callback function is the transformed haystacks array passed as the second argument.

The equivalent TypeScript is as follows:

function matchedSubstrings (haystacks: string[], needles: string[]): string[] {
  return needles.filter(function (this: string[], needle) {
    const lowerCaseNeedle = needle.toLowerCase()
    return this.some(haystack => haystack.includes(lowerCaseNeedle))
  }, haystacks.map(haystack => haystack.toLowerCase()))
}

const arrayA = ["apples", "Oranges", "salt", "Cracked Black Pepper"]
const arrayB = ["Salt", "pepper", "orange"]

console.log(matchedSubstrings(arrayA, arrayB))
Patrick Roberts
  • 49,224
  • 10
  • 102
  • 153