Home > Back-end >  Check if an array contains another array with the same ordering of elements
Check if an array contains another array with the same ordering of elements

Time:10-15

For example,

const target = [1,2,3,4,5,"abc", "def"]

test(target, [2,3,4]) === true
test(target, [4,5,"abc"]) === true
test(target, [0,1,2]) === false
test(target, ["abc",5,4]) === false
test(target, [2,4]) === false

Currently I'm using JSON.stringify to accomplish this (and with replacer function if the elements contain things like BigInt values):

`,${JSON.stringify(target).slice(1, -1)},`.includes(`,${JSON.stringify(arr).slice(1, -1)},`)

to check if target contains arr with the same ordering of elements, however this seems a bit too hacky so I wonder if there are better ways to accomplish it?

CodePudding user response:

To check for an ordered sub-array, including rejecting non-consecutive elements, we can use recursion: Array (A) is ordered inside another array (B) if first element of A is found, and if the rest of A, is inside the rest of B immediately after the found element.

function test(b, a, bIndex) {
  if (!a.length) return true;
  bIndex ??= b.findIndex(el => el === a[0]);
  return a[0] !== b[bIndex] ? false : test(b.slice(bIndex 1), a.slice(1), 0);
}

const target = [1,2,3,4,5,"abc", "def"]

console.log(test(target, [2,3,4]) === true)
console.log(test(target, [4,5,"abc"]) === true)
console.log(test(target, [0,1,2]) === false)
console.log(test(target, ["abc",5,4]) === false)
console.log(test(target, [2,4]) === false)

The original version, that isn't sensitive to non-consecutive elements, relaxing the immediately after constraint.

function isOrderedSubArray(b, a) {
  if (!a.length) return true;
  let index = b.findIndex(el => el === a[0]);
  return index === -1 ? false : isOrderedSubArray(b.slice(index   1), a.slice(1));
}

// testing it...

let bigArray = [0, 1, 2, 3, 4, 5, 6];
let smallA = [2, 5, 6];
let smallB = [2, 5, 12];
let smallC = [4, 3, 5];
let smallD = [6, undefined];

console.log(isOrderedSubArray(bigArray, smallA)===true)
console.log(isOrderedSubArray(bigArray, bigArray)===true)
console.log(isOrderedSubArray(bigArray, smallB)===false)
console.log(isOrderedSubArray(bigArray, smallC)===false)
console.log(isOrderedSubArray(bigArray, smallD)===false)

CodePudding user response:

You could get the start index and check every item of the second array.

const
    test = (a, b) => {
        let offset = a.indexOf(b[0]);
        while (offset !== -1) {
            if (b.every((v, i) => (i   offset) in a && v === a[i   offset])) return true;
            offset = a.indexOf(b[0], offset   1);
        }
        return false;
    },
    target = [1, 2, 3, 4, 5, "abc", "def"];

console.log(test(target, [2, 3, 4]));                  //  true
console.log(test(target, [4, 5, "abc"]));              //  true
console.log(test(target, [0, 1, 2]));                  // false
console.log(test(target, ["abc", 5, 4]));              // false
console.log(test(target, [2, 4]));                     // false
console.log(test(target, []));                         // false
console.log(test(target, [ "abc", "def", undefined])); // false
.as-console-wrapper { max-height: 100% !important; top: 0; }

CodePudding user response:

This could be tidied up but I think it will be quite performant.

  1. If the first element of the sub array does not appear in the target return false
  2. iterate over the target for the length of sub, from the starting position x
  3. If the position of the sub element is not equal to its relative position in the target element, or we go beyond the length of the target array, return false
  4. If all these checks pass return true

const target = [1,2,3,4,5,"abc", "def"]

function test(arr, sub) {
    x = arr.indexOf(sub[0])
    if(x < 0) return false;
 
    i = 0
    while(i < sub.length ) { 
    if(i != sub.indexOf(arr[x],i) || x >= arr.length) return false;
        x =1
        i =1
    }
    return true
}

console.log(test(target, [2,3,4]))// === true
console.log(test(target, [4,5,"abc"]))// === true
console.log(test(target, [0,1,2]))// === false
console.log(test(target, ["abc",5,4]))// === false
console.log(test(target, [2,4]))// === false
console.log(test(target, [])) // === false
console.log(test(target, [ "abc", "def", undefined ])) // === false
console.log(test([ 4, 5, 5, 6 ], [ 5, 5 ]))

CodePudding user response:

You can simply achieve this by just using Array.join() and then check the index by using String.indexOf() method.

As per the post, I am assuming you are searching only for the consecutive elements not a random one.

Live Demo :

const target = [1,2,3,4,5,"abc", "def"];

const search = [2,3,4];

const res = target.join().indexOf(search.join()) !== -1

console.log(res); // true

  • Related