Find the specific consecutive set of numbers in a Javascript array

Viewed 1703

I want to find a number of times an integer occurs consecutively in an array. I have found one example doing something similar:

const numbers = [0,0,0,296,296,0,0,296,296,296,0,0,0,0,0,293,293,293,293,293,293,293,293];

let chunks = [];

let prev = 0;
numbers.forEach((current) => {
  if ( current - prev != 1 ) chunks.push([]);

  // Now we can add our number to the current chunk!
  chunks[chunks.length - 1].push(current);
  prev = current;
});

chunks.sort((a, b) => b.length - a.length);

console.log('Longest consecutive set:', chunks[0]);
console.log('Size of longest consecutive set:', chunks[0].length);

I just want to get the number of longest consecutive of 0, like:

result: {
  key: 0
  longestConsecutive: 5
}

Any good solution? Thanks!

4 Answers

You can use Array.prototype.reduce to create an array of sequence lengths for your target value and then use Math.max to get the largest value in that array (which is the length of the longest sequence):

const numbers = [0,0,0,296,296,0,0,296,296,296,0,0,0,0,0,293,293,293,293,293,293,293,293];

function max_consecutive ( arr, value ) {
  return Math.max( ...numbers.reduce( (sequence_lengths, x) => {
      x === value ? sequence_lengths[0]++ : sequence_lengths.unshift(0);
      return sequence_lengths;
    }, [0]
  ) );
}

console.log( max_consecutive(  numbers, 0 ) );
console.log( max_consecutive(  numbers, 1 ) );
console.log( max_consecutive(  numbers, 293 ) );
console.log( max_consecutive(  numbers, 296 ) );

Perhaps you could do something like the following:

const numbers = [0,0,0,296,296,0,0,296,296,296,0,0,0,0,0,293,293,293,293,293,293,293,293,91];

function findConsecCount(value) {
  
  var startIndex = -1
  var result = 0
  
  for(var i = 0; i < numbers.length; i++) {
    
    if(numbers[i] === value) {
      if(startIndex === -1) {
        startIndex = i
      }
    }
    
    if(numbers[i] !== value) {
      if(startIndex !== -1) {
        result = Math.max(result, i - startIndex)
        startIndex = -1;
      }
    }
  }
      
  if(numbers[numbers.length - 1] === value) {
    if(startIndex !== -1) {
      result = Math.max(result, i - startIndex)
      startIndex = -1;
    }
  }
  
  return {
    key : value, 
    longestConsecutive : result
  }
}

console.log( findConsecCount(0) )
console.log( findConsecCount(293) )
console.log( findConsecCount(296) )
console.log( findConsecCount(91) )

You can also group "chunk" lengths by key using reduce and then sort them for each key:

const numbers = [0, 0, 0, 296, 296, 0, 0, 296, 296, 296, 0, 0, 0, 0, 0, 293, 293, 293, 293, 293, 293, 293, 293];

let consecutiveGroups = numbers.reduce((acc, curr, i, arr) => {
  if (!(curr in acc)) acc[curr] = [];
  if (arr[i - 1] != curr) acc[curr].push(1);
  else acc[curr][acc[curr].length - 1] += 1;
  return acc;
}, {});

Object.values(consecutiveGroups)
      .forEach(g => g.sort((a, b) => b - a));

console.log(consecutiveGroups);
console.log('longest consecutive 0s', consecutiveGroups[0][0]);
console.log('longest consecutive 296s', consecutiveGroups[296][0]);

[The update to using lengths instead of arrays of numbers was inspired by @Paulpro's fantastic solution]

I feel like this might be a case where a simple while loop is the easiest to understand and should be quite quick. This just runs two indexes up the array keeping track of the longest sequence found:

const numbers = [0, 0, 0, 296, 296, 0, 0, 296, 296, 296, 0, 0, 0, 0, 0, 293, 293, 293, 293, 293, 293, 293, 293];


function longestConsecutive(searchedFor, numbers) {
  let start = stop = longest = 0

  while (start < numbers.length + 1) {
    if (numbers[start] !== searchedFor) {
      longest = start - stop > longest ? start - stop : longest
      stop = start + 1
    }
    start++
  }
  return longest
}

console.log(longestConsecutive(0, numbers))
console.log(longestConsecutive(296, numbers))
console.log(longestConsecutive(293, numbers))

Related