1

If I have a list l1=["A","B","C"], and I have another list l2=["X","Y","Z","A","B","C","1","2","3"], how can I efficiently check if l1 appears in l2, with order as well.

In this case it does appear in the list, but instead if l1 was ["A","C","B"], then it would not. Or if it was l2=["X","Y","Z","A","D","B", "C","1","2","3"] this should also not be found as it has to be sequential too.

Thanks

omega
  • 30,811
  • 68
  • 188
  • 388
  • 2
    Possible duplicate of [Check if every element in one array is in a second array](https://stackoverflow.com/questions/8628059/check-if-every-element-in-one-array-is-in-a-second-array) – Sterling Archer Nov 20 '17 at 22:48
  • It should be based on order and be sequential too. – omega Nov 20 '17 at 22:49
  • idk maybe I'm just feeling extra lazy, but I'd probably just make the array a string by joining them with ".*" and then passing that to a regex object and testing that regex against the string form of l2 – Jhecht Nov 20 '17 at 22:51
  • But is that efficient? – omega Nov 20 '17 at 22:51
  • probably not, but it should work. – Jhecht Nov 20 '17 at 22:52

4 Answers4

3

function check(l1, l2) {
 return !!~l2.join('').indexOf(l1.join(''))
}
console.log(check(["A","B","C"], ["X","Y","Z","A","B","C","1","2","3"]));
console.log(check(["A","B","C"], ["X","Y","Z","A","D","B", "C","1","2","3"]));

Update

Here it how this is works:

l1.join('') and l2.join('') is convert the array to a string join on MDN

.indexOf part tell us where is the poison of the l2 string in the l1 indexOf on MDN

~ trick is a Bitwise NOT operator without going into the details, it is convert -1 to 0 and 0 to -1 in Java-Script every number is true except 0

!! (Double negation) is convert Number type to Boolean type What is the !! (not not) operator in JavaScript?

Peter
  • 1,586
  • 13
  • 25
  • Whats the `!!~` ? – omega Nov 20 '17 at 22:49
  • 1
    For my own enrichment, could you explain what your code is doing? Especially that tilde... – Andrew Nov 20 '17 at 22:50
  • Wouldn't the two nots cancel out? – omega Nov 20 '17 at 22:51
  • `~` is the binary NOT operator, this is a codegolf solution. Peter, please explain what is going on here for those not used to dissecting unreadable code? – Sterling Archer Nov 20 '17 at 22:51
  • And is this really an efficient solution? What if the array had millions of items? – omega Nov 20 '17 at 22:52
  • @omega if the array gets into sizes that big, consider using a Set instead. Much faster! – Sterling Archer Nov 20 '17 at 22:52
  • @Sterling Archer `~` with `indexOf` is really useful because convert `-1` to `0` and `0` to `-1` (and other numbers too but it is not important here), because of that we know it is found or not, (but not the position) `!!` is for convert numbers to Boolean, if you don't like it you can use: `return (l2.join('').indexOf(l1.join('')) !== -1)` – Peter Nov 20 '17 at 22:53
  • But a set doesn't care about ordering? But also a set is newer js syntax, I am limited by making it work on IE10. – omega Nov 20 '17 at 22:56
  • @omega It does care about the order because it turns both arrays into strings and then checks if the first string exists (as is) inside the second string. And it appears to work in IE10. – agrm Nov 20 '17 at 22:58
  • 1
    You should use `join(',')`. With `.join('')` you'll consider `["a", "bc"]` equal to `["ab", "c"]`. – Barmar Nov 20 '17 at 23:04
  • 2
    But even with comma, you'll consider `["a,b"]` equal to `["a", "b"]`. – Barmar Nov 20 '17 at 23:05
  • there is a lots of things what can improve on this code example: check 1st array is bigger than 2nd one, check both parameter is an array etc..., I just come up with this answer based on the specification in the question. – Peter Nov 20 '17 at 23:10
  • Peter, please take the time to explain your code, what it does and *how*; while it's a beautifully concise answer (albeit with imperfections) there's no simple means for the OP, or future users, to understand what's going on or learning from your answer, which is the whole point of the Q&A format. – David says reinstate Monica Nov 22 '17 at 14:05
  • @DavidThomas I updated my answer. English is not my 1st language, but i try to be clear. – Peter Nov 22 '17 at 16:12
1

You could use every() method and store index of first element if found in second array and then just increment that index and check if it exists in second array.

var l1 = ["A", "B", "C"]
var l2 = ["X", "Y", "Z", "A", "B", "C", "1", "2", "3"]

var check = l1.every(function(e, i) {
  if (i == 0) {
    var start = l2.indexOf(e);
    if (start == -1) return false;
    else {
      this.start = start;
      return true;
    }
  } else {
    return e == l2[this.start += 1]
  }
}, {});

console.log(check)

Update: You can also use every() and some().

var l1 = ["A", "B", "C"]
var l2 = ["X", "A", "Z", "A", "B", "C", "1", "2", "3"]

function check(arr1, arr2) {
  return arr2.some(function(e, i) {
    if (e == arr1[0]) {
      return arr1.every((a, j) => a == arr2[i + j])
    }
  })
}


console.log(check(l1, l2))
Nenad Vracar
  • 102,378
  • 14
  • 116
  • 136
  • Does this check for ordering and sequantialness? – omega Nov 20 '17 at 22:53
  • `return this.start = start` should be `this.start = start`; return true`. And `!start` should be `start == -1`. – Barmar Nov 20 '17 at 23:17
  • The problem in both cases is that `indexOf` returns `0` when it finds the match at the beginning of the array, and `0` is falsey. – Barmar Nov 20 '17 at 23:18
  • Another case that fails: if the first element of `l1` is repeated in `l2`: `l2 = [""X", "A", "Z", "A", "B", "C", "1", "2", "3"]` because `indexOf(e)` will only find the first occurrence. – Barmar Nov 21 '17 at 00:34
  • @Barmar Could you take a look at update and let me know what you think. – Nenad Vracar Nov 22 '17 at 10:35
  • Better, and simpler, too. No special case like `if (i == 0)`. – Barmar Nov 22 '17 at 16:53
0

I used this, and it seems to work fine. Does anyone see any issues?

        var l1 = ["A", "B", "C"]
        var l2 = ["X", "Y", "Z", "a", "B", "C", "1", "2", "3"]


        console.log(search(l1,l2,0));


        function CIindexOf(lst, val, offset) {
            var lVal = val.toLowerCase();
            for(var i=offset; i<lst.length; i++) {
                if (lst[i].toLowerCase() == lVal) return i;
            }
            return -1;
        }
        function search(l1, l2, offset) {
            if (l1.length == 0) return 0;
            var index = CIindexOf(l2, l1[0], offset);
            if (index == -1) return -1;
            for (var i=1; i<l1.length; i++) {
                if (l1[i].toLowerCase() != l2[index+i].toLowerCase()) return search(l1, l2, index+1);
            }
            return index;
        }
omega
  • 30,811
  • 68
  • 188
  • 388
-1

This version has a good performance (no callbacks in methods), and work with any type of content.

function isContain(arr1, arr2) {
 var arr2Length = arr2.length;
 if (arr2Length > arr1.length) return false; // quick check if arr2 is bigger than arr1 is always false
 var lastPos = -1;
 var i;
 while (~(lastPos = arr1.indexOf(arr2[0], lastPos + 1))) {
  for (i = 0; i < arr2Length; i++) {
   if (arr1[lastPos + i] !== arr2[i]) break;
  }
  if (i === arr2Length ) return true;
 }
 return false;
}

console.log(isContain(["X","Y","Z","A","B","C","1","2","3"], ["A","B","C"]));
console.log(isContain(["X","Y","Z","A","D","B", "C","1","2","3"], ["A","B","C"]));
console.log(isContain(["X","Y","Z","A","B","C","1","2","3"], ["AB","C"]));
console.log(isContain(["X","Y","Z","AB","C","1","2","3"], ["AB","C"]));
console.log(isContain([false, false, true, false, false, true], [true, true]));
console.log(isContain([false, false, true, false, false, true], [true, false]));
console.log(isContain([false, false, true, false, false, true], [1, 0]));
console.log(isContain([1, 1], [1, 1, 1]));
Peter
  • 1,586
  • 13
  • 25