I need to write a small map/reduce function that should return 1 if there are at least 4 continuous 0 in an array, otherwise it should return something different than 1.
Example:
[6, 7, 5, 0, 0, 0, 0, 3, 4, 0, 0, 1] => 1
[6, 7, 5, 0, 0, 0, 3, 4,0, 0, 0, 0, 0, 1] => 1
[5, 0, 0, 0, 3, 4, 0, 0, 8, 0, 0, 1] => something # 1
This is my algorithm:
[6, 7, 5, 0, 0, 0, 0, 3, 4, 0, 0, 1]
.map((i) => i === 0 ? 1 : 0)
.reduce((prev, i) => {
if (i !== 0) {
return prev + i;
} else {
if (prev >= 4) {
return 4;
}
return 0;
}
}, 0);
The .map method will mark 0 as 1 and non-0 as zero. So [6, 7, 5, 0, 0, 0, 0, 3, 4, 0, 0, 1] becomes [0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0]. Then the .reduce method will collect the number of zeroes.
If the current element is 1 (meaning zero in the input array) it returns the previous value plus the current value (1). This means it represents the number of zeroes. If the current item is 0 (meaning not 0 in the input array), it resets prev to 0 when it is less than 4, otherwise it carries on.
At the end, if the value is 4, it means that there are at least 4 continuous 0.
The algorithm seems to run, but not meet the requirement. It requires returning 1 if the input has 4 consecutive 0, otherwise it should return any non-zero number.
Do you think of any way to do this?
Here's an ES6 function that uses a 4-bit representation, where each 1-bit represents a non-zero value in the input array.
Only the most recent 4 bits are retained: each iteration the next bit is shifted in from the right, while the left most is dropped, always keeping 4 bits. If the outcome becomes zero at any time, the loop stops:
function has0000(arr) {
let c = 1;
return +!arr.every( n => c = (c*2+!!n) & 0xF );
}
console.log(has0000([6, 7, 5, 0, 0, 0, 0, 3, 4, 0, 0, 1]));
console.log(has0000([6, 7, 5, 0, 0, 0, 3, 4, 0, 0, 1]));
Your code
Although the algorithm for counting zeroes is correct, the return value is not a 1 when needed, and vice versa.
The return value is whatever is the last returned value in the reduce callback, so it represents a count, which could be any non-negative number.
Even when there are 4 consecutive zeroes found, this count can start from zero again, and so you lose the knowledge that you actually had a match.
The main fix to this is to swap the if statements, and do the if (prev >= 4) first. That way you will keep the count at 4 once it reaches that, no matter what follows. It will never get reset to 0 anymore.
The second fix is to detect the final return is exactly 4 and transform that to a one. This must be done in a way that 4 is the only value that gets transformed to a 1, nothing else. This you could do by dividing by 4.
So without changing anything else, with minimal changes, this is the corrected code:
var res = [6, 7, 5, 0, 0, 0, 0, 3, 4, 0, 0, 1]
.map((i) => i === 0 ? 1 : 0)
.reduce((prev, i) => {
if (prev >= 4) {
return 4;
} else if (i !== 0) {
return prev + i;
} else {
return 0;
}
}, 0) / 4;
console.log(res);
The downside of sticking to only map and reduce is that you cannot exit before having gone through all input elements. This is a pity, because once you have found 4 zeroes, there really is no reason to keep going. The result is already final at that moment.
And here is your corrected code in a more condensed format, where I also left out the map as it is a trivial thing to incorporate in the reduce callback:
var res = [6, 7, 5, 0, 0, 0, 0, 3, 4, 0, 0, 1]
.reduce((prev, i) => prev >= 4 ? 4 : i ? 0 : prev + 1, 0)
/ 4;
console.log(res);
You could use Array#some and a this object for counting.
Array#some allows to end the iteration if the right count is found, as opposite of Array#reduce, which iterates all elements.
function isContinuous(array) {
return +array.some(function (a, i) {
if (a === 0) {
this.count++;
return this.count === 4;
}
this.count = 0;
}, { count: 0 });
}
console.log(isContinuous([6, 7, 5, 0, 0, 0, 0, 3, 4, 0, 0, 1]));
console.log(isContinuous([6, 7, 5, 0, 0, 0, 3, 4, 0, 0, 0, 0, 0, 1]));
console.log(isContinuous([5, 0, 0, 0, 3, 4, 0, 0, 8, 0, 0, 1]));
In general, your implementation looks good to me, except the small nuance: you should specify -3 as an initial value for the reduce function (and modify its body accordingly in order to satisfy your requirements).
Below provided the modified version of your implementation, which returns 1 in case if there are present at least 4 consecutive zeroes, and otherwise returns one of the following values: -3, -2, -1 or 0
var result = [6, 7, 5, 0, 0, 0, 0, 3, 4, 0, 0, 1]
.map((i) => i === 0 ? 1 : 0)
.reduce((prev, i) => {
if (prev === 1) {
return 1;
}
if(i === 0) {
return -3;
}
return prev + (i === 1);
}, -3);
console.log(result)
Using .map and .reduce to meet your requirement:
//the following returns 1 if there is at least 4 consecutive 0's
//otherwise returns 0, 2, 4 or 6:
function cons4zeroes(arr) {
return arr
.map((i) => i ^ 0 ? 0 : 2)
.reduce((p, i) => p ^ 1 ?
i ^ 0 ?
(p + i) % 7 :
0 :
1,
0)
}
console.log(
cons4zeroes([6, 7, 5, 0, 0, 0, 0, 3, 4, 0, 0, 1]), " => 1"
);
console.log(
cons4zeroes([6, 7, 5, 0, 0, 0, 3, 4, 0, 0, 0, 0, 0, 1]), " => 1"
);
console.log(
cons4zeroes([5, 0, 0, 0, 3, 4, 0, 0, 8, 0, 0, 1]), " => something # 1"
);
This solution builds on your logic, but maps each 0 to 2 instead of 1, reserving 1 for when 4 consecutive 0's have been found. Then, summing the consecutive 2's, resetting to 0 if a non-zero value is found before the 4th zero, taking the sum modulo 7 to convert the sum to 1 when 4 zeroes are found (4 × 2 = 1 mod 7).
Alternative without .map():
//the following returns 1 if there is at least 4 consecutive 0's
//otherwise returns 0, 2, 4 or 6:
function cons4zeroes(arr) {
return arr.reduce((p, i) => p ^ 1 ?
i ^ 0 ? 0 : (p + 2) % 7 : 1, 0)
}
console.log(
cons4zeroes([6, 7, 5, 0, 0, 0, 0, 3, 4, 0, 0, 1]), " => 1"
);
console.log(
cons4zeroes([6, 7, 5, 0, 0, 0, 3, 4, 0, 0, 0, 0, 0, 1]), " => 1"
);
console.log(
cons4zeroes([5, 0, 0, 0, 3, 4, 0, 0, 8, 0, 0, 1]), " => something # 1"
);
Related
I have an array containing numbers, in that array there're some numbers that occur many times in consecutive order one after the other, and I want to compress those repeated numbers into a very specific format 'Number*Times' to reduce the size of the array:
input: [0, 1, 2, 0, 0, 0, 3, 2, 0, 0, 0, 0, 0, 0, 5, 6, 0]
---------^^^^^^^^^-----^^^^^^^^^^^^^^^^^^^--------
output: [0, 1, 2,'0x3', 3, 2, '0x6', 5, 6, 0]
let array = [0, 1, 2, 0, 0, 0, 3, 2, 0, 0, 0, 0, 0, 0, 5, 6, 0];
let string = array.toString();
let string_compressed = string.replace(/(\d+,)(\1)+/g, (x) => {
return "Number*" + x.split(",").length + ",";
});
let array_compressed = string_compressed
.split(",")
.map((x) => (isNaN(Number(x)) ? x : Number(x)));
console.log(array_compressed); //[0, 1, 2, 'Number*4', 3, 2, 'Number*7', 5, 6, 0]
I don't know how to get the number that repeated so I put Number instead!
I used regex to solve it, I know if you think to solve problem with regex, they become two problems!
BUT Guys I'm sure this isn't the efficient way to solve this problem, And there're other ways to solve it!
what do you suggest if you want to solve this problem?
Because your regex to find how many numbers repeat already only matches numbers that are in consecutive order in your array, you can simply just take the first index of the x.split(",") array and return that.
Edit:
Also, as #qrsngky out, your x.split(",").length wasn't actually the right length, because when you split it by comma, there is a null character at the end:
let array = [0, 1, 2, 0, 0, 0, 3, 2, 0, 0, 0, 0, 0, 0, 5, 6, 0];
let string = array.toString();
let string_compressed = string.replace(/(\d+,)(\1)+/g, (x) => {
console.log(x.split(","));
return "Number*" + x.split(",").length + ",";
});
let array_compressed = string_compressed
.split(",")
.map((x) => (isNaN(Number(x)) ? x : Number(x)));
console.log(array_compressed);
Sorry for missing that, and props to the comments! I just fixed it by subtracting one from the length.
Edit 2:
For edge cases, we can just add a comma and use slice.
I attached the complete fixed code snippet below:
let array = [0, 1, 2, 0, 0, 0, 3, 2, 0, 0, 0, 0, 0, 0, 5, 6, 0, 0, 0];
let string = array.toString() + ",";
let string_compressed = string.replace(/(\d+,)(\1)+/g, (x) => {
return x.split(",")[0] + "*" + (x.split(",").length - 1) + ",";
});
let array_compressed = string_compressed
.slice(0, -1)
.split(",")
.map((x) => (isNaN(Number(x)) ? x : Number(x)));
console.log(array_compressed);
Assume your original array consists of none other than numbers.
Non-regex approach: based on a for loop and counting how many repetitions had been encountered.
let array = [0, 1, 2, 0, 0, 0, 3, 2, 0, 0, 0, 0, 0, 0, 5, 6, 0]
let buffer = [];
let currentNum = array[0], count = 1;
for (let i = 1; i < array.length; i++) {
if (array[i] === currentNum) {
++count;
} else {
buffer.push( count === 1 ? currentNum : (currentNum + 'x' + count) );
currentNum = array[i];
count = 1;
}
}
//don't forget the last number
if(currentNum !== undefined) buffer.push( count === 1 ? currentNum : (currentNum + 'x' + count) );
console.log(buffer);
The if(currentNum !== undefined) check is only useful in case it's an empty array.
Another example of how not to do it with string manipulation by coding what you want done:
function packArray(array) {
var packed = [];
for( var i = 0; i < array.length; i=j) {
var entry = array[i];
for(var j = i+1; array[j] === entry && j<array.length; ++j);
packed.push( j > i+1 ? `${entry}x${j-i}` : entry);
}
return packed;
}
console.log( packArray([0, 1, 2, 0, 0, 0, 3, 2, 0, 0, 0, 0, 0, 0, 5, 6, 0]))
You could substitute let for var except for var j which should remain the same to allow access to j outside the nested for loop.
I am trying to use array.reduce on an array representing a single binary value. For instance [1,0,1] in binary would convert to 5 in decimal.
I have been able to succesfully convert between binary and decimal using a while loop, but would like to upgrade my code to use the reduce method.
What I have implemented so far is accurate up to 6 elements in the array. I am not sure why, but after 6 digts, the conversion fails.
In addition, I am using a formula to make the conversion. For example: to convert 111001 to decimal, you would have to do (1*2^5) + (1*2^4) (1*2^3) + (0*2^2) + (0*2^1) + (1*2^0).
const getDecimalValue = function (head) {
let total = head.reduce(
(sum) =>
sum + (head.shift() * Math.pow(2, head.length))
)
return total
}
console.log(getDecimalValue([1, 0, 1]) == 5)
console.log(getDecimalValue([1, 1, 1, 0, 0, 1]) == 57)
console.log(getDecimalValue([1, 1, 1, 0, 0, 1, 1]) == 115)
console.log(getDecimalValue([0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0]) == 7392)
console.log(getDecimalValue([1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0]) == 18880)
This was my code using the while loop
let sum = 0
while ((i = head.shift()) !== undefined) {
sum += (i * Math.pow(2, head.length))
console.log(i * Math.pow(2, head.length))
}
return sum
You could reduce the array and multiply last value and add the actual value.
const getDecimalValue = array => array.reduce((r, v) => r * 2 + v, 0);
console.log(getDecimalValue([1, 0, 1]) == 5)
console.log(getDecimalValue([1, 1, 1, 0, 0, 1]) == 57)
console.log(getDecimalValue([1, 1, 1, 0, 0, 1, 1]) == 115)
console.log(getDecimalValue([0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0]) == 7392)
console.log(getDecimalValue([1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0]) == 18880)
The problem is that you are mutating the array as reduce is iterating over it. This changes the array underneath, so the operation gets out of sync with the underlying values. Here is a (somewhat loose) illustration of how reduce normally walks the array:
arr = [1, 2, 3]
^ ^ ^
| | |
iteration 1 -- | |
iteration 2 ----- |
iteration 3 --------
Here is what happens when you modify it each iteration:
//start
arr = [1, 2, 3]
//at iteration 1
[2, 3] _
^
|
iteration 1 --
//at iteration 2
[3] _ _
^
|
iteration 2 -----
//at iteration 3
[] _ _
^
|
iteration 3 ------
Instead, the straight forward way to get your functionality is to make each item a power of 2 that is equal to the reverse index of the item
//index: 0 1 2 3
arr = [1, 0, 1, 0]
//reverse index: 3 2 1 0
And conveniently, to get that, you simply need to subtract 1 from the array length (because indeces are 0-based and length = 1 only has index = 0) and then subtract the normal index. This gives you the powers of two each value represents:
//reverse index: 3 2 1 0
arr = [1, 0, 1, 0]
//power of 2: 8 4 2 1
//multiply and sum: 8 + 0 + 2 + 0 = 10
And here is the code using reduce:
const getDecimalValue = function (head) {
let total = head.reduce(
(sum, item, index, array) =>
sum + item * Math.pow(2, (array.length - index - 1)),
// reverse index ^^^^^^^^^^^^^^^^^^^^^^^^
0
)
return total
}
console.log(getDecimalValue([1, 0, 1]) == 5)
console.log(getDecimalValue([1, 1, 1, 0, 0, 1]) == 57)
console.log(getDecimalValue([1, 1, 1, 0, 0, 1, 1]) == 115)
console.log(getDecimalValue([0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0]) == 7392)
console.log(getDecimalValue([1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0]) == 18880)
I find it way more readable using the following function with Array.prototype.reduceRight().
function binaryToDecimal(arr) {
let decimal = 0;
arr.reduceRight((base, binaryNum) => {
if (binaryNum === 1) {
decimal += base;
}
base = base * 2;
return base;
}, 1);
return decimal;
}
binaryToDecimal([1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0])===3462
Write a function that takes an array of values and moves all elements that are zero to the end of the array, otherwise preserving the order of the array. The zero elements must also maintain the order in which they occurred.
Zero elements are defined by either 0 or "0". Some tests may include elements that are not number literals.
NOT allowed to use any temporary arrays or objects. Also not allowed to use any Array.prototype or Object.prototype methods.So no array.push or splice() is allowed.
I tried this:
function removeZeros(nums) {
for(let i = nums.length - 1; i >= 0 ; i--){
if(nums[i] === 0){
nums.splice(i, 1);
nums.push(0);
}
}
return nums;
}
input:
[7, 2, 3, 0, 4, 6, 0, 0, 13, 0, 78, 0, 0, 19, 14]
Expected:
[7, 2, 3, 4, 6, 13, 78, 19, 14, 0, 0, 0, 0, 0, 0]
Actual:
[7, 2, 3, 4, 6, 13, 78, 19, 14, 0, 0, 0, 0, 0, 0]
Result is coming as correct but I need to do it without array.push() or array.splice()
Take length of original array
Filter nonZero values from original array
add zeros at the end as per difference in length of filtered array and original array
function removeZeros(nums) {
let originalLen = nums.length
let nonZero = nums.filter(Boolean)
return [...nonZero,...new Array(originalLen-nonZero.length).fill(0)]
}
console.log(removeZeros([7, 2, 3, 0, 4, 6, 0, 0, 13, 0, 78, 0, 0, 19, 14]))
Also not allowed to use any Array.prototype or Object.prototype
methods
function removeZeros(nums) {
let originalLen = nums.length
let final = []
for(let i=0;i<nums.length; i++){
if(nums[i]) final = [...final, nums[i]]
}
let lenDiff = originalLen-final.length
while(lenDiff){
final = [...final,0]
lenDiff--
}
return final
}
console.log(removeZeros([7, 2, 3, 0, 4, 6, 0, 0, 13, 0, 78, 0, 0, 19, 14]))
You could use sort:
const arr = [7, 2, 3, 0, 4, 6, 0, 0, 13, 0, 78, 0, 0, 19, 14]
arr.sort((a, b) => (a === 0) - (b === 0))
console.log(arr)
Subtracting booleans returns a 1, -1 or 0.
true - false === 1
false - true === -1
true - true === 0
If a is 0 and b isn't, 1 will be returned and a will be moved to the end of the array. If both a and b are zero or non-zero, they aren't moved relative to each other.
The simplest way to move certain items to one end is to collect the items to 2 separate arrays based on the condition and concatenate them in the end.
const arr = [7, 2, 3, 0, 4, 6, 0, 0, 13, 0, 78, 0, 0, 19, 14],
zeros = [],
nonZeros = []
for (const n of arr) {
if (n === 0)
zeros.push(n)
else
nonZeros.push(n)
}
const output = nonZeros.concat(zeros);
console.log(output)
Use a for loop, iterate through the array, and use a simple conditional to check zeroes.
var arr = [7, 2, 3, 0, 4, 6, 0, 0, 13, 0, 78, 0, 0, 19, 14];
var prev_zero_index = 0;
for (let i = 0; i < arr.length; i++) {
if (arr[i] != 0 && arr[i - 1] == 0) {
prev_zero_index++;
arr[prev_zero_index] = arr[i];
arr[i] = 0;
}
}
function pushZeros(arr) {
let count = 0;
for (let i = 0; i < arr.length; i++) {
if (arr[i] !== 0) arr[count++] = arr[i];
}
while (count < arr.length) arr[count++] = 0;
return arr;
}
Basically I am looping through all elements of array, picking nonzero element as I loop and storing it from 0th position in same array. After I am done looping, count will be equal to total nonzero elements in array. Rest all can be then initialized to zero.
You can simply do something like this:
let data = [7, 2, 3, 0, 4, 6, 0, 0, 13, 0, 78, 0, 0, 19, 14]
let result = data.sort((a,b) => !!b-!!a)
console.log(result)
Where you would sort on the boolean value of each of the array entries. We cast to boolean via the double negation operator. Since !!0 would be false and every other number would be true and we sort in a descending order (hence b-a and not a-b) we get the desired result.
Please note that Array.sort mutates the current array and if you want to create a new one simply use Array.slice like this:
let data = [7, 2, 3, 0, 4, 6, 0, 0, 13, 0, 78, 0, 0, 19, 14]
let sortZeroesLast = arr => arr.slice().sort((a,b) => !!b-!!a)
console.log(data) // <-- original array
console.log(sortZeroesLast(data)) // <-- new sorted array
You could use the sort() to sort the list based on its equality to 0, like this!
let numbers = [7, 2, 3, 0, 4, 6, 0, 0, 13, 0, 78, 0, 0, 19, 14];
numbers.sort((a, b) => {
if (b === 0) return -1;
return 1;
});
console.log(numbers); //[7, 2, 3, 4, 6, 13, 78, 19, 14, 0, 0, 0, 0, 0, 0]
I want to sort an array of integers by moving all elements with a value of 2 or greater to the end of the array. However, if I'm comparing two elements that are both 2 or greater, or that are both less than 2, then I want to keep them in their current order. I'm using the following comparison function with the native .sort():
function customSort(a, b) {
return (a >= 2 && b < 2) ? 1 : -1;
}
It seems to work as intended for the following cases:
[2, 3, 2, 0] => [0, 2, 3, 2]
[2, 3, 2, 0, 0, 0, 1, 0, 0, 0] => [0, 0, 0, 1, 0, 0, 0, 2, 3, 2]
But it looks like once I get past 10 elements, it seems to randomly order the elements that are less than 2, and the elements that are 2 or greater:
[2, 3, 2, 0, 0, 0, 1, 0, 0, 0, 0] => [0, 0, 0, 0, 0, 1, 0, 0, 3, 2, 2]
(expected result) => [0, 0, 0, 1, 0, 0, 0, 0, 2, 3, 2]
I assumed the -1 in the ternary operator would always keep the left element left and thus keep the order (as opposed to 0 which would understandably order them randomly). I'm aware there's a better way to sort without using the native .sort(), but I'm just curious about the behavior and if there's some way I could change the comparison function to get this working correctly with the native .sort().
A way to do it without sorting is to loop over it and append items greater that one to one array and other items to another and join them.
var arr = [2, 3, 2, 0, 0, 0, 1, 0, 0, 0, 0];
var shifted = [].concat.apply([],arr.reduce( function (arr, val, ind){
var ind = val > 1 ? 1 : 0;
arr[ind].push(val);
return arr;
},
[[],[]]));
I've done some console logging of what happens in the sort method and I've come to the conclusion that when the sort iterates over the array, it will reiterate over any elements that have moved position again with your comparison function. The fact that your conditional is a bit more specific, and in a large array makes it very hard to keep track of what's going on. I've used your first example and logged the result of the ternary operator and the array as it's being sorted. You get the following:
[2, 3, 2, 0]
-1
[2, 3, 2, 0]
-1
[2, 3, 2, 0]
1
[2, 3, 2, 2]
1
[2, 3, 3, 2]
1
[0, 2, 3, 2]
When you sort through [2, 3, 2, 0, 0, 0, 1, 0, 0, 0], it goes through 29 iterations. When you add that extra 0 at the end of the array, it goes through 58 iterations. During that extra 29 I'd imagine it'll shuffle the elements backwards and forwards using your conditionals. That may explain why you're not getting the results you expect.
Very similar to epascarello's answer, only it uses reduceRight to loop over the array backwards. Where a member >= 2 is encountered, it's spliced and pushed to the end of the array.
This should be efficient as the array is modified in place, no new array is created whereas epascarello's creates 6 additional arrays (including the result of concat).
var data = [2, 3, 2, 0, 0, 0, 1, 0, 0, 0, 0].reduceRight(function(acc, n, i, data) {
if (n >= 2) data.push(data.splice(i, 1));
return data;
}, null);
document.write(data); // [0, 0, 0, 1, 0, 0, 0, 0, 2, 3, 2]
I'm trying to create something that can detect if multiple values are in a array, this is what I tried to use, but that always returns true
row7 = [1, 1, 1, 1, 1, 1, 1, 1];
var field = [row0, row1, row2, row3, row4, row5, row6, row7];
console.log(field[0,1]); // Get the first item in the array
var needles = [1, 1, 1, 1]
console.log(needles)
var haystack = field[0,row7]
console.log(haystack)
console.log(contains(haystack,needles));
function contains(haystack, needles) {
return needles.map(function (needle) {
return haystack.indexOf(needle);
}).indexOf(-1) == -1;
}
Case true:
row 7 = [1, 1, 1, 1, 1, 1, 1, 1]
Checked for (four in a row):
needles = [1, 1, 1, 1]
And false:
row7 = [1, 1, 0, 1, 0, 0, 0, 1]
Edit:
Entire array:
/* Array containing the playing field 8 x 8
C0 C1 C2 C3 C4 C5 C6 C7
R0[0][0][0][0][0][0][0][0]
R1[0][0][0][0][0][0][0][0]
R2[0][0][0][0][0][0][0][0]
R3[0][0][0][0][0][0][0][0]
R4[0][0][0][0][0][0][0][0]
R5[0][0][0][0][0][0][0][0]
R6[0][0][0][0][0][0][0][0]
R7[0][0][0][0][0][0][0][0]
*\
var row0 = [0, 0, 0, 0, 0, 0, 0, 0],
row1 = [0, 0, 0, 0, 0, 0, 0, 0],
row2 = [0, 0, 0, 0, 0, 0, 0, 0],
row3 = [0, 0, 0, 0, 0, 0, 0, 0],
row4 = [0, 0, 0, 0, 0, 0, 0, 0],
row5 = [0, 0, 0, 0, 0, 0, 0, 0],
row6 = [0, 0, 0, 0, 0, 0, 0, 0],
row7 = [0, 0, 0, 0, 0, 0, 0, 0];
var field = [row0, row1, row2, row3, row4, row5, row6, row7];
Is there any way to achieve this using plain JS?
Thanks in advance.
I think that the easiest (not the most efficient) solution is to firstly convert both arrays into a string and then check if one string is a sub-string of another one:
function contains(array1, array2) {
if(array1 == null || array2 == null)
return false;
return array1.toString().contains(array2.toString());
}
var row7 = [1, 1, 1, 1, 1, 1, 1, 1];
var needles = [1, 1, 1, 1];
contains(row7, needles); //returns true
row7 = [1, 1, 0, 1, 0, 0, 0, 1]
contains(row7, needles); //returns false
UPDATE:
I've just realized that contains function is not supported by all browsers. So it is better to use indexOf i.e. return array1.toString().indexOf(array2.toString()) != -1;
change your contains method to
function contains(haystack, needles)
{
return haystack.join(",").indexOf(needle.join(",")) != -1;
}
Explanation -
do a join of needle to get "1,1,1,1"
and the join of haystack to get "1,1,1,1,1,1,1,1"
when you do indexOf you will get 0 since needles is contained in haystack
You can use Array.prototype.every() with an offset for the search.
function check(haystack, needles) {
var offset = 0;
while (offset + needles.length <= haystack.length) {
if (needles.every(function (a, i) {
return haystack[i + offset] === a;
})) {
return true;
}
offset++;
}
return false;
}
var row7 = [1, 1, 1, 1, 1, 1, 1, 1],
row8 = [1, 1, 0, 1, 0, 0, 0, 1],
needles = [1, 1, 1, 1];
document.write(check(row7, needles) + '<br>');
document.write(check(row8, needles) + '<br>');