Problem
I am trying to write a function to determine whether an array contains consecutive numbers for at least N numbers. For example, the input is [1,5,3,4]
and 3
, it turns true
because the array has 3
consecutive numbers, which is [3,4,5]
Here this function requires sorting beforehand and it is not the most eloquent solution in my opinion. Can someone take a look and suggest some improvements on this?
function hasConsecutiveNums(array, N) {
if (array.length < N) return false;
if (N === 0) return true;
const sortedArray = array.slice().sort((a, b) => a - b);
let count = 0;
let prev = null;
for (const num of sortedArray) {
if (prev && num === prev + 1) {
count++;
} else {
count = 1;
}
if (count === N) return true;
prev = num;
}
return false;
}
console.log(hasConsecutiveNums([1, 4, 5, 6], 3)) // true
console.log(hasConsecutiveNums([1, 4, 5, 6], 4)) // false
Solution
One issue to consider: what if an element in the array is 0, and thus falsey? Then if (prev &&
will not be fulfilled:
console.log(hasConsecutiveNums([-1, 0, 1], 3)) // false... oops
Another tweak to make the code a bit more elegant would be to assign prev
to the first element of the array first, and initialize count
to 1
, thus starting comparison on the second element rather than on the first, avoiding the need to compare against null
.
With this method, you also need to return true
immediately if the array’s length is only 1, like the other answer recommends, otherwise there won’t be any iterations within which return true
could be reached:
If, as the comment notes, you’d want [1, 2, 2, 3]
to return true
, de-duplicate the numbers with a Set:
function hasConsecutiveNums(array, N) {
if (array.length < N) return false;
if (N <= 1) return true;
const sortedArray = [...new Set(array.slice().sort((a, b) => a - b))];
let prev = sortedArray.shift();
let count = 1; // first element of the array is already in prev
for (const num of sortedArray) {
if (num === prev + 1) {
count++;
} else {
count = 1;
}
if (count === N) return true;
prev = num;
}
return false;
}
console.log(hasConsecutiveNums([1, 4, 5, 6], 3)) // true
console.log(hasConsecutiveNums([1, 4, 5, 6], 4)) // false
console.log(hasConsecutiveNums([-1, 0, 1], 3)) // true
console.log(hasConsecutiveNums([1, 2, 2, 3], 3)) // true
Some quick remarks:
if (N === 0) return true;
can be replaced by
if (N <= 1) return true;
because in a non-empty array each element is a single “consecutive number.” This saves the sorting of the array in the case N=1.
Then it suffices to check the count again only if it has been incremented.
The comparison with the previous number (or null
) can be simplified slightly.
for (const num of sortedArray) {
if (prev === num - 1) {
count++;
if (count === N) return true;
} else {
count = 1;
}
prev = num;
}