1

Let's say i have array 1

const arr1 = [[45, 63],[89],[90]]

and array 2

const arr2 = [45, 63]

To check if arr2 or values from arr2 exist in arr1 it's easy doing the next function

private contains(arr1, opts) {
    const stringifiedOpts = JSON.stringify(opts);
    return arr1.some(item => JSON.stringify(item) === stringifiedOpts);
}

in this case contains() function will return true.

This was first simplest case. Now let's say that:

arr2 = [45, 63, 90]

function contains() will return false because arr1 doesn't contain [45, 63, 90] but contains [90] as different array. In this case function should return true because 90 from arr2 exist in arr1

My question it's what kind of logic should i have in that function to return true when:

arr2 = [45, 63, 90] or

arr2 = [45, 90] or

arr2 = [63, 89] or

arr2 = [63, 90] or

arr2 = [81, 20, 90] or

arr2 = [25, 60, 89]

because 90 or 89 exist in arr1 but as different arrays

Any help/ideas/solutions here are welcome guys. Thanks!

ConstantinEx
  • 160
  • 3
  • 16
  • 2
    [Flatten the array](https://stackoverflow.com/questions/10865025/merge-flatten-an-array-of-arrays-in-javascript) and then simply search through it. – 31piy Dec 14 '17 at 09:24
  • Why do `[81, 20, 90]` and `[25, 60, 89]` should return `true`. `arr1` doesn't have any values that contain `20` or `81` or `25` or `60` – Titus Dec 14 '17 at 09:30
  • 1
    @Titus but it contains 90 or 89 – ConstantinEx Dec 14 '17 at 09:34
  • I guess I misunderstood the description. I thought that the function should only return `true` when `arr1` contains all the values of `arr2`, even if they are in separate arrays. – Titus Dec 14 '17 at 09:37

3 Answers3

2

This seems to work:

arr1
  .map(arr => arr.join())
  .some(arr => arr2.join().includes(arr))
Peter Shev
  • 88
  • 2
  • 6
1

Here is a version without flattening to keep the structure and it basically checks for each block in arr1 if it's compliant with arr2.

const arr1 = [[45, 63],[89],[90]];

function contains(arr, opts) {
    for(let i=0; i<arr.length; i++) {
       let innerArray = arr[i];
       let isThisBlockOk = true;
       for(let j=0; j<innerArray.length; j++) {
           if(opts.indexOf(innerArray[j]) === -1) {
               isThisBlockOk = false;
               break;
           }
       }
       if(isThisBlockOk) return true;
    }
    return false;
}

const listOfArr2 = [
  [45, 63], 
  [45, 63, 90],
  [45, 63, 90],
  [45, 90],
  [63, 89],
  [63, 90],
  [81, 20, 90],
  [25, 60, 89],
  [45, 64, 91],
  [45]
];

listOfArr2.forEach(arr2 => {
  console.log(JSON.stringify(arr2) + ' contains return: '+ contains(arr1, arr2));
});
sjahan
  • 5,720
  • 3
  • 19
  • 42
  • Well, i think we shouldn't use flatten method because if arr1 = [[45, 63],[89],[90]] and arr2 = [45] then it should be false because in arr1 45 can be just with 63 togeter – ConstantinEx Dec 14 '17 at 10:13
  • I'm gonna check this, BRB! – sjahan Dec 14 '17 at 10:17
  • The trouble is `arr2` is always flatten, for instance `arr2 = [45, 63, 90]` must return `true`, but if I understand properly, `arr2 = [45, 64, 91]` must return `false`. The thing is from `arr2`, we cannot determine how to group its elements to match `arr1`, so we are forced to bruteforce it and test every combination. Is that what you want? On large data, the perfs are probably gonna be ugly. – sjahan Dec 14 '17 at 10:24
  • And one more thing here, let's say arr1 = [[12,43,54,65],[46],[90]] then if arr2 = [12,43,54,65] function should return true if arr2 = [12,43,54] function should return false because in arr1 these numbers - 12,43,54 can't be without 65 if arr2 = 12,43,54,90 function should return true because 90 exist in other children array from arr1 – ConstantinEx Dec 14 '17 at 10:29
  • This new version is not bruteforce, so the perfs must be quite acceptable, and it must fit your requirements. It's quite ugly though, it could certainly be improved but I have to go right now so here is a first version ;) i'll try to take some time to improve it later! Check at the end, I added some test cases where it should fail. – sjahan Dec 14 '17 at 10:40
  • maybe i can create in other way arr2 So, how i create the arr2? I have a list of checkboxes `{{checkbox.value}}` and the onChangeSave function `public async onChangeSave(question, elemId) { const selectedValues = question.questionOptions.filter(o => o.selected).map(o => o.id); }` so selectedValues it's my arr2. The problem is that i can't now how to group the items here, and it can be just flatten array... – ConstantinEx Dec 14 '17 at 10:41
  • That's definitely the problem: on one side, you have structured data and on the other, you have flatten data. Check the last version of my post, I think it'll fit your need ;) – sjahan Dec 14 '17 at 10:46
  • take a look at Peter answer, it works perfect, and the code it's so clean ))))) – ConstantinEx Dec 14 '17 at 10:55
0

Is this what you want? I'm guessing and need your feedback

const arr1 = [
  [45, 63],
  [89],
  [90]
]

document.write(custom_contains_any(arr1, [63, 88]))
document.write('<br>')
document.write(custom_contains_all(arr1, [63, 90]))

function custom_contains_any(source, search) {
  const s1 = flaten(source)
  const s2 = flaten(search)
  return s2.filter((x) => s1.includes(x)).length
}

function custom_contains_all(source, search) {
  const s1 = flaten(source)
  const s2 = flaten(search)
  return s2.every((x) => s1.includes(x))
}

function flaten(arr) {
  let rtn = []
  arr.forEach((x) => {
    if (Array.isArray(x)) {
      rtn = [...rtn, ...flaten(x)]
      return
    }
    rtn = [...rtn, x]
  })
  return rtn
}
Josh Lin
  • 2,397
  • 11
  • 21