0

I have array with some element that I want to check if some element combination exist in array that target element is following by any element of checkingSet, if yes, then return true otherwise, return false. For example, if inputArray is ['a', 'b', 'c', 'd'] and looking for combination is ['a', 'd'] then it should return true because inputArray has both in the right sequence. if inputArray is ['d', 'b', 'c', 'd', 'a'] and the combination is ['a', 'd'], then it should be false because inputArray includes both elements but in wrong order or

isExist(['a', 'd']) => true 
isExist(['a', 'a', 'd']) => true
isExist(['e', 'd']) => false

I can use Set and while loop but I am wondering if any more elegant or modern way to do?

export function isExist(checkArray): boolean {
  let hasA = false;
  let hasB = false;
  checkingSet = new Set(['b', 'c', 'd'])
  const target = 'a'
  inputArray = [...checkArray]
  while (inputArray && !!inputArray.length) {
    const lastOne = inputArray.pop();
    if (!hasA && !!lastOne) {
      hasA = chekcingSet.has(lastOne);
    }
    if (!hasB && !!lastOne) {
      hasB = lastOne === target;
    }
    if (hasA && hasB) {
      return true;
    }
  }
  return false;
}

jacobcan118
  • 7,797
  • 12
  • 50
  • 95

2 Answers2

1

To check that the array contains 'a', and after this 'a' at least one of ['b', 'c', 'd'] is in the array you can do this. First, get the index of the first 'a' in the array, then check if some value of ['b', 'c', 'd'] is included in that array after this start index.

function doesExist(arr) {
  const startPos = arr.indexOf('a')
  if (startPos < 0)
    return false
  return ['b', 'c', 'd'].some(char => arr.includes(char, startPos + 1))
}

console.log(doesExist(['a', 'd']))
console.log(doesExist(['a', 'a', 'd']))
console.log(doesExist(['e', 'd']))
console.log(doesExist(['d', 'a']))
A_A
  • 1,832
  • 2
  • 11
  • 17
0

This is the general version, it's O(n).

function doesDupleExistInOrder([el1, el2], arr) {
    let index = arr.indexOf(el1)
    if (index == -1) return false;
    return arr.includes(el2, index + 1)
}

console.log(doesDupleExistInOrder(["a", "d"], ["a", "b", "c", "d", "e"])); // true
console.log(doesDupleExistInOrder(["a", "b"], ["a", "b", "c", "d", "e"])); // true
console.log(doesDupleExistInOrder(["d", "e"], ["a", "b", "c", "d", "e"])); // true

console.log(doesDupleExistInOrder(["d", "a"], ["a", "b", "c", "d", "e"])); // false
console.log(doesDupleExistInOrder(["d", "a"], ["a"]));                     // false
console.log(doesDupleExistInOrder(["d", "a"], []));                        // false

If you want a specific version then just curry the general function AKA:

let doesADExist = arr => doesDupleExistInOrder(["a", "d"], arr);
console.log(doesADExist(["a", "b", "c", "d", "e"]));  // true
Arik
  • 374
  • 3
  • 7
  • I think if you use `arr.indexOf(el1)` to get the first i (and checking for -1) and then `arr.includes(el2, i+1)` it would be a bit shorter and easier to read – A_A Jul 01 '21 at 16:07
  • @A_A, Perhaps, but that requires two loops through the array in the worst case, this requires only one. Also it's only 5 lines, so any reasonable programmer could figure out what this is doing in less than a minute, and it's a faster algorithm. – Arik Jul 01 '21 at 16:08
  • I don't think so. From my understanding `indexOf(el1)` would iterate until it finds the element at some index `i`. And `arr.includes(el2, i+1)` would start iterating at position `i+1`. So at worst it should be n steps (and for sure still O(n)). Also these methods could be optimized by the browser, but I'm not sure about that – A_A Jul 01 '21 at 16:10
  • 1
    Hmm ok, I forgot you could plug in an index for includes. I will edit my post. – Arik Jul 01 '21 at 16:13