I wanted to write a function to find a contiguous subarray within a given array from a given starting index and return the index of the subarray within the array if it's found, and -1 if it's not found. This is similar to String.indexOf, but for arrays and subarrays instead of strings and substrings.
This is my working code:
var find_csa = function (arr, subarr, from_index) {
if (typeof from_index === 'undefined') {
from_index = 0;
}
var i, found, j;
for (i = from_index; i < 1 + (arr.length - subarr.length); ++i) {
found = true;
for (j = 0; j < subarr.length; ++j) {
if (arr[i + j] !== subarr[j]) {
found = false;
break;
}
}
if (found) return i;
}
return -1;
};
And these are my tests and their expected values:
console.log(find_csa([1, 2, 3, 4, 5], [2, 3, 4]) === 1);
console.log(find_csa([1, 2, 3, 4, 5], [5]) === 4);
console.log(find_csa([1, 2, 3, 4, 5], [1, 3]) === -1);
console.log(find_csa([1, 2, 3, 4, 5], [42]) === -1);
console.log(find_csa([1, 2, 3, 4, 5], []) === 0);
console.log(find_csa([3, 4, 3, 4, 3, 4], [3, 4, 3], 1) === 2);
console.log(find_csa([6, 6, 6, 7], [6, 6, 7]) === 1);
console.log(find_csa([12, 9, 16, 42, 7, 866, 3], [16, 42, 7, 866]) === 2);
My code passes the tests, but as you can see, it uses a boolean value found in the inner loop which is just my messy, ad-hoc way of continuing an outer loop from a nested loop. is there a cleaner way of writing it? I looked into Array.prototype.findIndex but it is an experimental technology at the moment so I can't use it. I want a method that works in most browsers. I know there is a "polyfill" code snippet written on the Mozilla page, but that is even longer than my current code and it will be slower due to the function calls, so I'd rather avoid it.
My primary goal for this function is performance (the subarrays will be very small, so I believe that using Boyer-Moore string search algorithm or tries is a tad overkill), and then my secondary goal is elegance of my implementation. With those two goals in mind, I would like to know if there is a better way of writing this code, or if there are any JavaScript features or functions that I'm missing that could help me avoid the found boolean.
JSFiddle if it helps anyone: http://jsfiddle.net/qc4zxq2p/
Are there any JavaScript features or functions that I'm missing that could help me avoid the found boolean
Yes, you can use a label on your outer loop:
function find_csa(arr, subarr, from_index) {
var i = from_index >>> 0,
sl = subarr.length,
l = arr.length + 1 - sl;
loop: for (; i<l; i++) {
for (var j=0; j<sl; j++)
if (arr[i+j] !== subarr[j])
continue loop;
return i;
}
return -1;
}
This is the same as yours, just prettified a bit (at least to my aesthetics):
var find_csa = function (arr, subarr, from_index) {
from_index = from_index || 0;
var i, found, j;
var last_check_index = arr.length - subarr.length;
var subarr_length = subarr.length;
position_loop:
for (i = from_index; i <= last_check_index; ++i) {
for (j = 0; j < subarr_length; ++j) {
if (arr[i + j] !== subarr[j]) {
continue position_loop;
}
}
return i;
}
return -1;
};
The inner loop can be reduced to a single line using the array method every:
if(subarr.every(function(e, j) { return (e === arr[i + j]); })
return i;
or (ES6 proposal):
if(subarr.every( (e, j) => (e === arr[i + j]) ))
return i;
But this may be just a curiosity or educational example, unless you don't care about performance.
Inside your loop, you can eliminate the found variable and avoid continue like this:
for (j = 0; j < subarr.length; ++j) {
if (arr[i + j] !== subarr[j]) break;
}
/*
* the above loop breaks in two cases:
* normally: j === subarr.length
* prematurely: array items did not match
* we are interested in kowing if loop terminated normally
*/
if (j === subarr.length) return i;
Having said that, here is my solution using Array.join and String.indexOf. This is only good for array of Numbers:
function find_csa(arr, subarr, from_index) {
from_index |= 0;
if (subarr.length === 0) {
return from_index;
}
var haystack = "," + arr.slice(from_index).join(",") + ",",
needle = "," + subarr.join(",") + ",",
pos = haystack.indexOf(needle);
if (pos > 0) {
pos = haystack.substring(1, pos).split(",").length + from_index;
}
return pos;
}
console.log("All tests should return true");
console.log(find_csa([1, 2, 3, 4, 5], [1, 2, 3]) === 0);
console.log(find_csa([1, 2, 3, 4, 5], [2, 3, 4]) === 1);
console.log(find_csa([1, 2, 3, 4, 5], [5]) === 4);
console.log(find_csa([1, 2, 3, 4, 5], [6]) === -1);
console.log(find_csa([1, 2, 3, 4, 5], [1, 3]) === -1);
console.log(find_csa([6, 6, 6, 7], [6, 6, 7]) === 1);
console.log(find_csa([1, 2, 3, 4, 5], []) === 0);
console.log(find_csa([3, 4, 3, 4, 3, 4], [3, 4, 3], 1) === 2);
console.log(find_csa([1, 2, 3, 4, 5], [], 1) === 1);
Reading initial discussion based on zerkms proposition, I was interested to try a solution using JSON.stringify, despite the unfavorable opinions.
Then I finally got a solution, which passes all tests properly.
Probably not the faster method, but surely the shortest one:
var find_csa = function (arr, subarr, from_index) {
var start=from_index|0,
needle=JSON.stringify(subarr),
matches=JSON.stringify(arr.slice(start)).
match(new RegExp('^\\[(.*?),?'+
needle.substr(1,needle.length-2).replace(/([\[\]])/g,'\\$1')
));
return !!matches?(matches[1].length?matches[1].split(',').length:0)+start:-1;
}
The above code accepts arrays of arrays, as suggested by Shashank, but fails to process items containing commas.
So I developped another solution which also accepts commas (thanks to Steven Levithan for the elegant tip about while(str!=(str=str.replace(regexp,replacement)));).
But it is only for fun, since:
the code is not so short, now... Sigh!
it probably consumes a lot of CPU time
it doesn't properly work with empty items (they are ignored)
I suspect (and didn't dig deeper :-) it might fail with complex objects as items
Anyway, here is it:
var find_csa = function (arr, subarr, from_index) {
var start=from_index|0,
commas=new RegExp('(?:(\')([^,\']+),([^\']+)\'|(")([^,"]+),([^"]+))"'),
strip_commas='$1$2$3$1$4$5$6$4',
haystack=JSON.stringify(arr.slice(start)),
needle=JSON.stringify(subarr).replace(/^\[(.*)\]$/,'$1');
while(haystack!=(haystack=haystack.replace(commas,strip_commas)));
while(needle!=(needle=needle.replace(commas,strip_commas)));
matches=haystack.match(new RegExp('^\\[(.*?),?'+needle.replace(/([\[\]])/g,'\\$1')));
return !!matches?(matches[1].length?matches[1].split(',').length:0)+start:-1;
}
i fixed this question with this code:
getCount(arr)
{
const chunked = [];
for(let i=0; i<arr.length; i++) chunked[i] = [];
let sub = 0;
for (let i = 1; i < arr.length; i++) {
if (arr[i]>arr[i-1]) {
chunked[sub].push(...[arr[i-1],arr[i]]);
} else {
sub++
}
}
const chunked2 = [...chunked.filter(k=>k.length).map(k => [...new Set(k)])];
for (let i = 0; i < chunked2.length; i++) {
if (chunked2[i+1])
if( chunked2[i][chunked2[i].length - 1] > chunked2[i+1][0]) {
chunked2[i+1].shift();
}
}
return [].concat.apply([], chunked2).lenght;
}
Related
I wrote a solution that allows me to get an array of indexes from the first array which is the intersection of indexes from two sorted arrays and I'd like to know why this solution is wrong. When I check it I get the correct array of indexes from the first array but the interviewer told me that this is wrong.
Thanks a lot for the help and explanations. I have no commercial experience yet. Sorry for some mistakes in English, as I am from Ukraine and I improve this language.
// first example of input:
// const arr1 = [1, 2, 2, 2];
// const arr2 = [1, 1, 2, 2];
// second example of input:
const arr1 = [1, 2, 2, 3, 4, 5, 6, 7, 9, 9, 20];
const arr2 = [1, 2, 3, 3, 5, 8, 9, 9, 21];
// first example of output:
// - [0, 1, 2]
// - [0, 1, 3]
// - [0, 2, 3]
// second example of output:
// - [0, 1, 3, 5, 8, 9]
// - [0, 2, 3, 5, 8, 9]
//function compareItemsFn, length1, length2 - from conditions to this task
const compareItemsFn = (index1, index2) => {
switch (true) {
case arr1[index1] === arr2[index2]: return 0;
case arr1[index1] < arr2[index2]: return -1;
case arr1[index1] > arr2[index2]: return 1;
default: return undefined;
}
};
const length1 = arr1.length;
const length2 = arr2.length;
// function intersectionIndexes - my solution
function intersectionIndexes(compareItemsFn, length1, length2) {
let indexesIntersectionArray = [];
let i = 0;
let j = 0;
while (i < length1 && j < length2) {
if (compareItemsFn (i, j) === 0) {
indexesIntersectionArray.push(i);
i++;
j++;
} else if (compareItemsFn (i, j) === 1) {
j++;
} else {
i++;
}
}
return indexesIntersectionArray;
};
const result = intersectionIndexes(compareItemsFn, length1, length2);
If you are certain that your solution works then perhaps it was not wrong in the sense that it gave the wrong answer but rather in the way you solved the problem.
The following code is a simplification of your solution. It takes the two arrays as parameters instead of the value of their length property so the solution isn't tied to the global variables arr1 and arr2. You should always favor implementing solutions that are generalised.
In place of your compareItemsFn function, the Math.sign() method from the standard library is used. Some times in interview situations you can be asked to implement functionality which can be found in the standard library and what the interviewer is looking to see is if you are aware of it.
function simplified(arrayOne, arrayTwo) {
let result = [];
let indexOne = 0;
let indexTwo = 0;
while (indexOne < arrayOne.length && indexTwo < arrayTwo.length) {
let signCheck = Math.sign(arrayOne[indexOne] - arrayTwo[indexTwo]);
if (signCheck == 0) {
result.push(indexOne);
indexOne++;
indexTwo++;
}
else if ( signCheck > 0) {
indexTwo++;
}
else {
indexOne++;
}
}
return result;
}
I am trying to write a function that will take an array and n as parameters,
it will return all subsets of that array with n elements, have tried a couple things, couldn't yet succeed.
thanks to whoever put it here, this functions is way too complicated and doesn't do the job, basically what I tried to do here is to pick out one element from a 4 element array to create its 3 element subsets. It doesn't even take N as parameter. it returns all 3 element subsets but also identical ones, so I have to filter them out as well, in any case I will keep trying.
function findSubsets(array) {
var answers = [];
var firstArray = array;
for (i = 0; i < array.length; i++) {
array = firstArray;
for (var k = 0; k < array.length; k++) {
if (k != i) {
var subset = array.splice(k, 1);
answers.push(array); array.splice(k, 0, subset[0]);
}
}
}
}
That not as complicated as it seems. This one is optimized because it doesn't creates useless temporary arrays during the process.
function findSubsets(array, n) {
var answers = [];
for(var i = 0 ; i < array.length ; i += n) {
answers.push(array.slice(i, i + n));
}
return answers;
}
findSubsets([1, 2, 3, 4, 5, 6, 7, 8, 9], 2) // --> [[1, 2], [3, 4], [5, 6], [7, 8], [9]]
findSubsets([1, 2, 3, 4, 5, 6, 7, 8, 9], 3) // --> [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
You can try this solution
var subsetArray = (function() {
return {
getResult: getResult
}
function getResult(array, n) {
function isBigEnough(value) {
return value.length === n;
}
var ps = [
[]
];
for (var i = 0; i < array.length; i++) {
for (var j = 0, len = ps.length; j < len; j++) {
ps.push(ps[j].concat(array[i]));
}
}
return ps.filter(isBigEnough);
}
})();
var arr = [1, 2, 3, 4,5,6,7,8,9];
console.log(subsetArray.getResult(arr,2));
The task:
You are given 3 sorted arrays. You should find the smallest number
that is common in all 3 arrays and return it. If such a number doesn't
exist, return -1
My approach:
Use early exit: If one of the array is empty, then we know there won't be a common number in all arrays
Create pointer that points to the first element of the corresponding array
In the outer loop, loop through all elements of the first array. If any of the pointer over reaches the end of the array, then break the loop because we have reached the end and haven't found a common number
In the first inner loop check the second array for the element the pointer of the first array is pointing to
If you found it then set a flag. Otherwise remember the running index to the second pointer so we can continue at this element in the next iteration
If the flag is set, then loop through the second inner loop. In here it's analogous to the first inner loop: Search for the current element in the 3rd array.
If you find it, then immediately return the value. If not go to the next element until you find an element bigger than the current one
Increment the pointer of the first array
Do this until you reach either one of the array
My Solution:
let findLeastCommonNumber = function(a, b, c) {
if (a.length === 0 || b.length === 0 || c.length === 0) {
return -1;
}
let aPointer = 0;
let bPointer = 0;
let cPointer = 0;
while (aPointer < a.length ||
bPointer < b.length ||
cPointer < c.length) {
const aValue = a[aPointer];
let bFound = false;
for (let i = bPointer; i < b.length; i++) {
if (b[i] === aValue) {
bPointer = i;
bFound = true;
break;
}
if (b[i] > aValue) {
bPointer = i;
break;
}
}
if (bFound) {
for (let i = cPointer; i < c.length; i++) {
if (c[i] === aValue) {
return a[aPointer];
}
if (c[i] > aValue) {
cPointer = i;
break;
}
}
}
aPointer++;
}
return -1;
};
Sample solution:
let find_least_common_number = function(a, b, c) {
let i = 0;
let j = 0;
let k = 0;
while (i < a.length
&& j < b.length
&& k < c.length) {
// Finding the smallest common number
if (a[i] === b[j]
&& b[j] === c[k]) {
return a[i];
}
// Let's increment the iterator
// for the smallest value.
if (a[i] <= b[j]
&& a[i] <= c[k]) {
i++;
} else if (b[j] <= a[i]
&& b[j] <= c[k]) {
j++;
} else if (c[k] <= a[i]
&& c[k] <= b[j]) {
k++;
}
}
return -1;
};
I like the fact that the sample solution has less nesting. But the sample solution doesn't take advantage of an early exit and I think my solution is more scalable. Let's say the requirements changes, and 27 arrays more are now included. In my solution, I'd just copy the inner loops and change the pointer names only. I don't need to touch existing code. In the sample solution, however, I'd have touch every line of code that refers to one of the arrays and I would add the new arrays there. What do you think?
You could a completely dynamic approach for an infinite (sort of) count of arrays.
function findLeastCommonNumber(...array) {
var indices = array.map(_ => 0),
smallest = Math.max(...array.map((a, i) => a[indices[i]])),
next;
while (indices.every((i, j) => i < array[j].length)) {
next = smallest;
array.forEach((a, i) => {
while (indices[i] < a.length && a[indices[i]] < smallest)
next = Math.max(next, a[++indices[i]]);
});
if (array.every((a, i) => a[indices[i]] === smallest)) return smallest;
smallest = next;
}
return -1;
}
console.log(findLeastCommonNumber([1, 2, 3, 4, 5, 7], [8, 9, 10], [1, 2, 3, 5, 6, 7, 9]));
console.log(findLeastCommonNumber([1, 2, 3, 4, 5, 7, 9, 10], [1, 2, 3, 5, 6, 7, 9, 10], [4, 6, 7, 8, 9, 10, 11, 12]));
console.log(findLeastCommonNumber([1, 5, 6, 7, 8, 10], [5, 6, 9, 10], [1, 2, 3, 4, 5, 6, 9, 10]));
For the more readable solution, you can use this:
const findLeastCommonNumber = function() {
const total = [].concat(...arguments).sort((a,b) => a > b ? 1 : -1);
let index = 0;
let commonNumber = -1;
while(total.length - 2 > index && commonNumber === -1){
if(total[index] === total[index + 1] && total[index] === total[index + 2]){
commonNumber = total[index];
}
index++;
}
return commonNumber;
};
console.log(findLeastCommonNumber([1,5,6,7,8,10],[5,6,9,10],[1,2,3,4,5,6,9,10]));
An alternative solution - Take the 1st array, and convert the other arrays to Sets. Now use Array.find() on the 1st array, and check with Array.every() if the current number is found in all sets.
const findLeastCommonNumber = (main, ...array) => {
const sets = array.map(o => new Set(o));
const common = main.find(n => sets.every(s => s.has(n)));
return common === undefined ? -1 : common;
};
console.log(findLeastCommonNumber([1, 2, 3, 4, 5, 7], [8, 9, 10], [1, 2, 3, 5, 6, 7, 9]));
console.log(findLeastCommonNumber([1, 2, 3, 4, 5, 7, 9, 10], [1, 2, 3, 5, 6, 7, 9, 10], [4, 6, 7, 8, 9, 10, 11, 12]));
console.log(findLeastCommonNumber([1, 5, 6, 7, 8, 10], [5, 6, 9, 10], [1, 2, 3, 4, 5, 6, 9, 10]));
The arrays are sorted in ascending order. We will use three
iterators simultaneously to traverse each of the arrays. We can
start traversing each array from the 0^{th}index, which always has
the smallest value.
If the values pointed to by the three iterators are equal, that is
the solution. Since the arrays are sorted in ascending order, that
value must be the smallest value present in all of the arrays.
Otherwise, we see which of the three iterators points to the
smallest value and increment that iterator so that it points to the
next index.
If any of the three iterators reaches the end of the array before
we find the common number, we return -1.
let findLeastCommonNumber = function(arr1, arr2, arr3) {
// Initialize starting indexes for arr1, arr2 and arr3
let i = 0;
let j = 0;
let k = 0;
// Iterate through three arrays
while (i < arr1.length && j < arr2.length && k < arr3.length) {
// Finding the smallest common number
if (arr1[i] === arr2[j] && arr2[j] === arr3[k]) {
return arr1[i];
}
// Let's increment the iterator
// for the smallest value.
if (arr1[i] <= arr2[j] && arr1[i] <= arr3[k]) {
i++;
}
else if (arr2[j] <= arr1[i] && arr2[j] <= arr3[k]) {
j++;
}
else if (arr3[k] <= arr1[i] && arr3[k] <= arr2[j]) {
k++;
}
}
return -1;
};
let v1 = [6, 7, 10, 25, 30, 63, 64];
let v2 = [0, 4, 5, 6, 7, 8, 50];
let v3 = [1, 6, 10, 14];
console.log("Least Common Number: " + findLeastCommonNumber(v1, v2, v3));
I just got started with writing sorting algorithms.
Currently I am learning the Bubble Sort algorithm, I found the following online and it's working fine:
const arr = [3, 2, 6, 9, 3, 5];
const bubbleSort = array => {
do {
var isSorted = true;
for (var i = 0; i < array.length; i++) {
if (array[i] > array[i + 1]) {
var temp = array[i];
array[i] = array[i + 1];
array[i + 1] = temp;
isSorted = false;
}
}
} while(!isSorted)
return array
};
Output:
[ 2, 3, 3, 5, 6, 9 ]
However, when I try to write it using an if statement instead of a while loop like the following, it doesn't work as expected:
const arr = [3, 2, 6, 9, 3, 5];
const bubbleSort = (array) => {
let isSorted = false;
if(!isSorted) {
isSorted = true;
for(var i = 0; i < array.length; i++) {
if (array[i] > array[i + 1]) {
var temp = array[i + 1];
array[i + 1] = array[i];
array[i] = temp;
isSorted = false;
}
}
}
return array;
}
Output:
[ 2, 3, 6, 3, 5, 9 ]
What am I doing wrong here?
We need the while loop for bubble sort.
If we remove while then we will 'bubble' only once through the whole array. For example if the
[3, 2, 6, 9, 3, 5];
here 3 (first element) is larger than 2 (second element) so we swap them and now we have
[2, 3, 6, 9, 3, 5]
When we continue with the for loop we approach 3 (6th element) that is smaller so we swap it with 9 (5th element). AND continue forward.
[2, 3, 6, 3, 9, 5]
from here we will only go up but we can analyse the situation. We can see that 3 (4th element) is smaller than 6(third element) but the for loop is way ahead so we will not be in a situation where we swap it with a larger element.
So we have to start "bubbling" again from the beginning and we need to do it until everything is sorted. This will happen when there are nothing to swap, because we set isSorted=false when ever we swap. After array is sorted we will do a last pass where we will check every adjacent pair and if they are all sorted the swap will not occur and isSorted will be true
TLDR; we need while because 'bubbling' might need several passes through the array.
while loop is an easy way to implement Bubble Sort, otherwise you will need O(n²) algorithm with nested for loops instead, if else statements will not work:
const arr = [3, 2, 6, 9, 3, 5];
const bubbleSort = array => {
var length = array.length;
//Number of passes
for (var i = 0; i < length; i++) {
//Notice that j < (length - i)
for (var j = 0; j < (length - i - 1); j++) {
//Compare the adjacent positions
if(array[j] > array[j+1]) {
//Swap the numbers
var tmp = array[j]; //Temporary variable to hold the current number
array[j] = array[j+1]; //Replace current number with adjacent number
array[j+1] = tmp; //Replace adjacent number with current number
}
}
}
return array
}
bubbleSort(arr)
// expected output: [2, 3, 3, 5, 6, 9]
You can also see Bubble Sort pseudocode here: Bubble Sort Algorithm
Question has been moved to CodeReview: https://codereview.stackexchange.com/questions/154804/find-a-list-of-objects-in-an-array-with-javascript
Having an array of objects - such as numbers - what would be the most optimal (Memory and CPU efficiency) way if finding a sub group of objects? As an example:
demoArray = [1,2,3,4,5,6,7]
Finding [3,4,5] would return 2, while looking for 60 would return -1.
The function must allow for wrapping, so finding [6,7,1,2] would return 5
I have a current working solution, but I'd like to know if it could be optimized in any way.
var arr = [
1,
5,2,6,8,2,
3,4,3,10,9,
1,5,7,10,3,
5,6,2,3,8,
9,1]
var idx = -1
var group = []
var groupSize = 0
function findIndexOfGroup(g){
group = g
groupSize = g.length
var beginIndex = -2
while(beginIndex === -2){
beginIndex = get()
}
return beginIndex
}
function get(){
idx = arr.indexOf(group[0], idx+1);
if(idx === -1 || groupSize === 1){
return idx;
}
var prevIdx = idx
for(var i = 1; i < groupSize; i++){
idx++
if(arr[getIdx(idx)] !== group[i]){
idx = prevIdx
break
}
if(i === groupSize - 1){
return idx - groupSize + 1
}
}
return -2
}
function getIdx(idx){
if(idx >= arr.length){
return idx - arr.length
}
return idx
}
console.log(findIndexOfGroup([4,3,10])) // Normal
console.log(findIndexOfGroup([9,1,1,5])) // Wrapping
You could use the reminder operator % for keeping the index in the range of the array with a check for each element of the search array with Array#every.
function find(search, array) {
var index = array.indexOf(search[0]);
while (index !== -1) {
if (search.every(function (a, i) { return a === array[(index + i) % array.length]; })) {
return index;
}
index = array.indexOf(search[0], index + 1);
}
return -1;
}
console.log(find([3, 4, 5], [1, 2, 3, 4, 5, 6, 7])); // 2
console.log(find([6, 7, 1, 2], [1, 2, 3, 4, 5, 6, 7])); // 5
console.log(find([60], [1, 2, 3, 4, 5, 6, 7])); // -1
console.log(find([3, 4, 5], [1, 2, 3, 4, 6, 7, 3, 4, 5, 9])); // 6
.as-console-wrapper { max-height: 100% !important; top: 0; }
My take on the problem is to use slice() and compare each subarray of length equal to the group's length to the actual group array. Might take a bit long, but the code is short enough:
// The array to run the tests on
var arr = [
1,
5, 2, 6, 8, 2,
3, 4, 3, 10, 9,
1, 5, 7, 10, 3,
5, 6, 2, 3, 8,
9, 1
];
// Check arrays for equality, provided that both arrays are of the same length
function arraysEqual(array1, array2) {
for (var i = array1.length; i--;) {
if (array1[i] !== array2[i])
return false;
}
return true;
}
// Returns the first index of a subarray matching the given group of objects
function findIndexOfGroup(array, group) {
// Get the length of both arrays
var arrayLength = array.length;
var groupLength = group.length;
// Extend array to check for wrapping
array = array.concat(array);
var i = 0;
// Loop, slice, test, return if found
while (i < arrayLength) {
if (arraysEqual(array.slice(i, i + groupLength), group))
return i;
i++;
}
// No index found
return -1;
}
// Tests
console.log(findIndexOfGroup(arr,[4,3,10])); // Normal
console.log(findIndexOfGroup(arr,[9,1,1,5])); // Wrapping
console.log(findIndexOfGroup(arr,[9,2,1,5])); // Not found
If the group is longer than the array, some errors might occur, but I leave it up to you to extend the method to deal with such situations.