Lelouch
Lelouch

Reputation: 970

Check for a single consecutive character in an array

I have an array of numbers which can be a value of either 1 or 0. I need to create a function that detects if there is one instance where there is a consecutive 1 and no other 1 exist outside of that instance, returns true else false

So to sum it up here's a clearer view of the constraints to return true:

  1. must have only one set of consecutive 1
  2. there must be no other 1 outside of that one instance of consecutive 1

Test cases:

[0, 0, 1, 1, 0, 0] true

[1, 0, 1, 0, 0, 0] false

[1, 0, 1, 1, 0, 0] false

[1, 1, 0, 1, 1, 0] false

[0, 1, 1, 1, 1, 0] true

[0, 0, 1, 1, 1, 1] true

Upvotes: 1

Views: 95

Answers (2)

Trevor Dixon
Trevor Dixon

Reputation: 24372

function hasOneRun(arr) {
  let switches = 0;
  for (let i = 0; i < arr.length; i++) {
    switches += arr[i] ^ arr[i-1];
    if (switches > 2) return false;
  }
  return switches > 0;
}

Counts how many times it switches from 0 to 1 or 1 to 0. arr[i] ^ arr[i-1] is 1 only if the value changes from the previous value. If switches is 0 at the end, there were only 0s, so false. If it's greater than 2, then it switched to 1, then to 0, then back to 1, so there were too many runs.

Here's a fun one-liner :D

Math.ceil(arr.reduce((switches, val, i) => switches + (val ^ arr[i-1]))/2) === 1;

Edit: Some other ideas

const startOne = (el, i, arr) => el == 1 && arr[i-1] != 1;
const is1 = x => x === 1;

arr.filter(startOne).length == 1;
arr.findIndex(startOne) === arr.findLastIndex(startOne);
arr.slice(arr.findIndex(is1), arr.findLastIndex(is1)+1).every(is1)


/^0*1+0*$/.test(arr.join('')); // zero or more zeroes, one or more ones

Or if you treat it as a sequence of bits…

function hasOneRun(x) {
  while (!(x&1)) x >>= 1; // shift off trailing zeroes
  return (x&(x+1)) === 0; // see if one less than power of 2 (all 1s)
}
console.log(hasOneRun(0b001111000));
console.log(hasOneRun(0b11000));
console.log(hasOneRun(0b1111));
console.log(hasOneRun(0b1110000111000));

Upvotes: 3

Andrew Parks
Andrew Parks

Reputation: 8107

You can also solve this by treating it as a string, and splitting it up where there are any sequences of zeroes:

const testCases = [
  [[0, 0, 1, 1, 0, 0], true],
  [[1, 0, 1, 0, 0, 0], false],
  [[1, 0, 1, 1, 0, 0], false],
  [[1, 1, 0, 1, 1, 0], false],
  [[0, 1, 1, 1, 1, 0], true],
  [[0, 0, 1, 1, 1, 1], true]
];
const f = a => a.join('').split(/0+/).filter(i=>i).length===1;
testCases.forEach(t=>console.log(f(t[0])===t[1] ? 'pass' : 'fail'));

Upvotes: 1

Related Questions