Maximum conditions inside if in javascript - javascript

Is there any maximum limit of conditions for If in Javascript? I am using following method to detect bombs in division "b". But it skips more than 3 or 4 conditions and hence less bombcount than the actual count.
The following function triggers as soon as I click on div b where b = some number . It has a Kwhere I check for bomb in every cell and if the cell with the bomb satisfies the position criterion it increases bombcount by 1.
var i = 1;
var p1 = b-1;
var p2 = b+1;
var p3 = b+6;
var p4 = b-6;
var p5 = b-5;
var p6 = b+5;
var p7 = b-7;
var p8 = b+7;
var bombcount = 0;
while(i<37)
{
var check = document.getElementById(i).value;
if (check == "explode" && b>6 && b<31) {
if(i==p1 || i==p2 || i==p3 || i==p4 ||
i==p5 || i==p6 || i==p7 || i==p8) {
bombcount++
};
}
i++;
}

Use array for p and indexOf to check is i in array:
var p = [b - 1, b + 1, b + 6, b - 6, b + 5, b - 5, b + 7, b - 7];
if (p.indexOf(i) !== -1) {
bombcount++;
}

No, there is no limit to number of if-else statements, be it one after another or nested if-else loops. Also, there is as such no limit to number of condition you can have under a if statement.
But, it is better to use switch in those cases. It improves readability and performance.
For switch syntax see this
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Statements/switch
For using switch over a range of values see this previous post
Switch statement for greater-than/less-than

There is no limit. And as a tip, you maybe better off using switch and falling through for these conditions:
switch (i) {
case p1:
case p2:
case p3:
// your logic
break;
}
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Statements/switch

Related

JavaScript - Binary search hangs every time

I have a 2D array, something like the following:
[1.11, 23]
[2.22, 52]
[3.33, 61]
...
Where the array is ordered by the first value in each row.
I am trying to find a value within the array that is close to the search value - within a certain sensitivity. The way this is set up, and the value of the sensitivity, ensure only one possible match within the array.
The search value is the current x-pos of the mouse. The search is called on mousemove, and so is being called often.
Originally I had the following (using a start-to-end for loop):
for(var i = 0; i < arr.length; i++){
if(Math.abs(arr[i][0] - x) <= sensitivity){
hit = true;
break;
}
}
And it works like a charm. So far, I've only been using small data sets, so there is no apparent lag using this method. But, eventually I will be using much larger data sets, and so want to switch this to a Binary Search:
var a = 0;
var b = arr.length - 1;
var c = 0;
while(a < b){
c = Math.floor((a + b) / 2);
if(Math.abs(arr[c][0] - x) <= sensitivity){
hit = true;
break;
}else if(arr[c][0] < x){
a = c;
}else{
b = c;
}
}
This works well, for all of 2 seconds, and then it hangs to the point where I need to restart my browser. I've used binary searches plenty in the past, and cannot for the life of me figure out why this one isn't working properly.
EDIT 1
var sensitivity = (width / arr.length) / 2.001
The points in the array are equidistant, and so this sensitivity ensures that there is no ambiguous 1/2-way point in between two arr values. You are either in one or the other.
Values are created dynamically at page load, but look exactly like what I've mentioned above. The x-values have more significant figures, and the y values are all over the place, but there is no significant difference between the small sample I provided and the generated one.
EDIT 2
Printed a list that was dynamically created:
[111.19999999999999, 358.8733333333333]
[131.4181818181818, 408.01333333333326]
[151.63636363636363, 249.25333333333327]
[171.85454545454544, 261.01333333333326]
[192.07272727272726, 298.39333333333326]
[212.29090909090908, 254.2933333333333]
[232.5090909090909, 308.47333333333324]
[252.72727272727272, 331.1533333333333]
[272.94545454545454, 386.1733333333333]
[293.16363636363633, 384.9133333333333]
[313.3818181818182, 224.05333333333328]
[333.6, 284.53333333333325]
[353.81818181818187, 278.2333333333333]
[374.0363636363637, 391.63333333333327]
[394.25454545454556, 322.33333333333326]
[414.4727272727274, 300.9133333333333]
[434.69090909090926, 452.95333333333326]
[454.9090909090911, 327.7933333333333]
[475.12727272727295, 394.9933333333332]
[495.3454545454548, 451.27333333333326]
[515.5636363636366, 350.89333333333326]
[535.7818181818185, 308.47333333333324]
[556.0000000000003, 395.83333333333326]
[576.2181818181822, 341.23333333333323]
[596.436363636364, 371.47333333333324]
[616.6545454545459, 436.9933333333333]
[636.8727272727277, 280.7533333333333]
[657.0909090909096, 395.4133333333333]
[677.3090909090914, 433.21333333333325]
[697.5272727272733, 355.09333333333325]
[717.7454545454551, 333.2533333333333]
[737.963636363637, 255.55333333333328]
[758.1818181818188, 204.7333333333333]
[778.4000000000007, 199.69333333333327]
[798.6181818181825, 202.63333333333327]
[818.8363636363644, 253.87333333333328]
[839.0545454545462, 410.5333333333333]
[859.272727272728, 345.85333333333324]
[879.4909090909099, 305.11333333333323]
[899.7090909090917, 337.8733333333333]
[919.9272727272736, 351.3133333333333]
[940.1454545454554, 324.01333333333326]
[960.3636363636373, 331.57333333333327]
[980.5818181818191, 447.4933333333333]
[1000.800000000001, 432.3733333333333]
As you can see, it is ordered by the first value in each row, ascending.
SOLUTION
Changing the condition to
while(a < b)
and
var b = positions.length;
and
else if(arr[c][0] < x){
a = c + 1;
}
did the trick.
Your binary search seems to be a bit off: try this.
var arr = [[1,0],[3,0],[5,0]];
var lo = 0;
var hi = arr.length;
var x = 5;
var sensitivity = 0.1;
while (lo < hi) {
var c = Math.floor((lo + hi) / 2);
if (Math.abs(arr[c][0] - x) <= sensitivity) {
hit = true;
console.log("FOUND " + c);
break;
} else if (x > arr[c][0]) {
lo = c + 1;
} else {
hi = c;
}
}
This is meant as a general reference to anyone implementing binary search.
Let:
lo be the smallest index that may possibly contain your value,
hi be one more than the largest index that may contain your value
If these conventions are followed, then binary search is simply:
while (lo < hi) {
var mid = (lo + hi) / 2;
if (query == ary[mid]) {
// do stuff
else if (query < ary[mid]) {
// query is smaller than mid
// so query can be anywhere between lo and (mid - 1)
// the upper bound should be adjusted
hi = mid;
else {
// query can be anywhere between (mid + 1) and hi.
// adjust the lower bound
lo = mid + 1;
}
I don't know your exact situation, but here's a way the code could crash:
1) Start with an array with two X values. This array will have a length of 2, so a = 0, b = 1, c = 0.
2) a < b, so the while loop executes.
3) c = floor((a + b) / 2) = floor(0.5) = 0.
4) Assume the mouse is not within sensitivity of the first X value, so the first if branch does not hit.
5) Assume our X values are to the right of our mouse, so the second if branch enters. This sets a = c, or 0, which it already is.
6) Thus, we get an endless loop.

Euler Project 2 in Javascript

I am going through the Odin Project and part of that is doing questions 1-3 in the Euler project. I am stumped on question 2:
"By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms."
I am so frustrated! What am I doing wrong? Here's what I have so far. Thanks!
function f() {
var fib = [];
fib.push(1,2,3);
var i = fib.length;
var total = 0;
while(fib[i] < 4000000) {
var x = fib[i-2] + fib [i-1];
if(x % 2 == 0) {
total += x;
}
} return total;
}
console.log(f());
The fibonacci sequences starts 1, 1, 2, not 1, 2, 3.
Also, your solution looks like it will work, but you are storing every number in the sequence instead of just the last two, so this will gobble memory comparatively.
As #DLeh notes, the fibonacci sequence starts with 1,1,2 - not 1,2,3. However, that doesn't change the result of summing the even valued items. The problem you're having is that at this point:
while(fib[i] < 4000000) {
fib[i] is undefined, so the function immediately exits with the total staying at 0. Also within the while loop, you're not pushing the next item in the sequence into your array. The below code fixes both of these problems:
function f() {
var fib = [];
fib.push(1,1);
var i = fib.length;
var total = 0;
while(fib[i-1] < 4000000) {
var x = fib[i-2] + fib [i-1];
fib.push(x);
i = fib.length;
if(x % 2 == 0) {
total += x;
}
} return total;
}
console.log(f()); //4613732
#DLeh also pointed out that you're storing more numbers than needed, this solution works without using the array:
function f() {
var f1 = 1;
var f2 = 1;
var total = 0;
while (f2 < 4000000) {
var t = f1 + f2;
if (t % 2 == 0)
total += t;
f1 = f2;
f2 = t;
}
return total;
}
console.log(f()); //4613732
Just for grins, note that you can do this problem without any use of %, and just + operations. Every third value in the sequence is even. That is, 2 is followed by 3 (odd), and then 3 + 2 is 5 (odd), but that sum of two odd numbers gets us back to even (8) and the cycle repeats.
Thus:
function evenFibTotal(limit) {
var a = 1, b = 1, c = 2, total = 0;
while (c < limit) {
total += c;
a = b + c;
b = a + c;
c = a + b;
}
return total;
}
On each iteration, the second trailing value is set to the next value in the sequence (b + c), and that plus the current one is the first trailing value, and finally the next even Fibonacci number is the sum of those two.
(There's also the closed solution but it's no fun :)

The Optimal Urinal Strategy

Here is an interactive page describing the problem and an academic paper going over the mathematics.
The problem can be roughly described as follows.
Given an arbitrary-length array of boolean values representing n adjacent urinals, with values of true indicating occupied and values of false indicating vacant, how would you construct an algorithm to populate this array, given any configuration, while:
Maximizing the 'privacy' of each occupant by keeping one as far as possible from other urinators on either side.
Maintaining this privacy for as long as possible by ensuring the configuration becomes saturated at the last possible time.
Faced with multiple suboptimal choices, prioritizing urinals without an adjacent urinal on either side over a merely unoccupied adjacent urinal.
I marked this javascript for simplicity, but any code or pseudo-code would be fine.
var urinals = Array
.apply(null, new Array(n))
.map(Boolean.prototype.valueOf,false);
edit - found a related problem here:
Optimal Seating Arrangement Algorithm
As close as I have to a solution:
var urinalFinder = function(urinals){
var gaps = new Array(), last = null;
for(var i = 0; i < urinals.length; i++){
last = gaps.length ? gaps[gaps.length - 1] : 0;
if(last < 0 && !urinals[i] || last > 0 && !!urinals[i] || last == 0)
gaps.push(0); // push if new sequence of vacant or occupied
// negatives are occupied count & positives vacant count
gaps[gaps.length - 1] += !!urinals[i] ? -1 : 1;
}
// find the first index of the largest gap
var maxGapSize = Math.max.apply(Math, gaps),
maxGapGapsIdx = gaps.indexOf(maxGapSize),
isFirst = maxGapGapsIdx === 0,
isLast = maxGapGapsIdx === gaps.length - 1,
maxGapIdx = 0;
if(maxGapSize < 1) return false; // no gaps available
var gapPoint = maxGapSize > 3
? Math.ceil(maxGapSize / 3) // per xkcd suggestion
: isFirst && maxGapSize === 2
? 1
: isLast && maxGapSize === 2 ? 2 : Math.ceil(maxGapSize / 2);
// find where our chosen gap begins in input array
for(var i = 0; i < maxGapGapsIdx; i++)
maxGapIdx += Math.abs(gaps[i]);
var result = maxGapIdx + gapPoint - 1; // arrays are zero-indexed
return result;
};
For example, applied to filling an array of 9 vacant spaces will fill them like this:
var foo = [0,0,0,0,0,0,0,0,0]; // nine values
for(var i = 0; i < foo.length; i++)
foo[urinalFinder(foo)] = i+1;
[4, 6, 1, 7, 2, 8, 3, 9, 5]
Does not always produce optimal results (sometimes a different placement could allow saturation a few moves later) and does not favor end urinals, but does a pretty good job fanning values around and keeping a minimum buffer for just about as long as possible.

Summation\ Addition of two arrays (particular)

"A positive number of whatever length is represented as an array of numerical characters, ergo between '0's and '9's. We know that the most significant cypher is in position of index 0 of the array.
Example:
- Number is 10282
- Array will be number = [1,0,2,8,2]
This considered, create a function of 2 arrays representing two positive numbers that calculates the SUM\ADDITION\SUMMATION of both of them and set it in a third array, containing the sum of the first 2."
This is how the exercise is translated from my own language, italian.
This is my solution but it doesnt entirely work. I have tried with basic stuff like
A=[1,4] and B=[4,7]. The results should be C=[6,1] but it gives me [5,1] as it considers the line where I use the modular but not the one where I say that the -1 index position should take a ++.
Help <3
alert('Insert A length');
var k=asknum();
alert('Insert B length');
var h=asknum();
var A = new Array(k);
var B = new Array(h);
// asknum() is only defined in this particular environment we are
// using at the university. I guess the turnaround would be -prompt-
function readVet(vet){//inserts values in index positions
for(i=0;i<vet.length;i++)
vet[i]=asknum();
}
readVet(A);//fills array
readVet(B);//fills array
function sumArray(vet1,vet2){
var C = new Array();
for(i=vet1.length-1;i>(-1);i--){
for(n=vet2.length-1;n>(-1);n--){
C[i]=vet1[i]+vet2[i];
if(C[i]>9){
C[i]=C[i]%10;
C[i-1]=C[i-1]++;
}
}
}
return C;
}
print(sumArray(A,B));
I'm not sure what you're doing with a nested for loop here. You just need one. Also, to make said loop really simple, normalize the arrays first so that both are the length of the larger array + 1 element (in case of carry). Then correct the result on the way out of the function.
function normalizeArray(array, digits) {
var zeroCnt = digits - array.length,
zeroes = [];
while (zeroCnt--) {
zeroes.push(0);
}
return zeroes.concat(array);
}
function sumArrays(a1, a2) {
var maxResultLength = Math.max(a1.length, a2.length) + 1;
a1 = normalizeArray(a1, maxResultLength);
a2 = normalizeArray(a2, maxResultLength);
var result = normalizeArray([], maxResultLength);
var i = maxResultLength - 1, // working index
digit = 0, // working result digit
c = 0; // carry (0 or 1)
while (i >= 0) {
digit = a1[i] + a2[i] + c;
if (digit > 9) {
c = 1;
digit -= 10;
} else {
c = 0;
}
result[i--] = digit;
}
/* If there was no carry into the most significant digit, chop off the extra 0 */
/* If the caller gave us arrays with a bunch of leading zeroes, chop those off */
/* but don't be an idiot and slice for every digit like sqykly =D */
for (i = 0 ; i < result.length && result[i] === 0 ; i++) {
/* result = result.slice(1); don't do that, or anything */
}
return result.slice(i);
}
That gives the expected output.
I may be missing something because the other answers look much more complicated, but here's my attempt at providing an answer based on the question:
// Takes an array and generates the sum of the elements
function addArrayNumbers(arr) {
return arr.reduce(function (p, c) {
return String(p) + String(c);
});
}
// Sums two numbers and returns an array based on that sum
function addCombinedNumbers(a, b) {
return String(Number(a) + Number(b)).split('');
}
var arrone = [1, 4];
var arrtwo = [4, 7];
var one = addArrayNumbers(arrone);
var two = addArrayNumbers(arrtwo);
var c = addCombinedNumbers(one, two); // [6,1]
Fiddle
I followed a different approach that may very well be less efficient than yours, but i consider it to be much clearer. One important thing is that i reverse the arrays so the least significant bit is first. Comments are in the code.
function sum(a,b){
// ensure a is the largest of the two arrays
if (a.length < b.length)
return sum(b,a);
// flip the arrays so the least significant digit is first
a = a.reverse();
b = b.reverse();
// c will hold the result (reversed at first)
var c = [];
// add each number individually
var carry = a.reduce(function(carry,digitA,index){
// digitA is guaranteed to be a number, digit from b is not!
var sum = digitA + (b[index] || 0) + carry;
c.push(sum%10);
return Math.floor(sum/10); // this is carried to the next step of the addition
},0); // initial carry is 0
if (carry) c.push(1); // resolve if carry exists after all digits have been added
return c.reverse();
}
// Usage:
console.log(sum([1,0,8,3],[1,3,5])); // [1, 2, 1, 8]
console.log(sum([8,3],[7,9])); // [1, 6, 2]
PS: There are many problems with your code. For one, you cannot use two nested loops:
var a = [0,1];
var b = [2,3];
for (var i=0; i<a.length; i++) {
for (var j=0; j<b.length; j++) {
console.log(a[i] + ' ' + b[i]);
}
}
// will output: 0 2, 0 3, 1 2, 1 3
// you want something along the lines of: 0 2, 1 3
What you want is a single loop that iterates over both arrays simultaneously.
My attempt at an efficient solution:
function efficientSum(a,b){
var i = a.length, j = b.length;
if (i<j) return efficientSum(j,i);
var q = 0, c = [];
c.length = i;
while (i) {
c[--i] = a[i] + (b[--j] || 0) + q;
q = c[i] > 9 ? ((c[i]-=10),1) : 0; // comma operator, ugly!
}
if (q) c.unshift(1);
return c;
}

Finding the nth item in a repeating list of fixed items

I have to determine the mathematical formula to calculate a particular repeating position in a series of numbers. The list of numbers repeats ad infinitum and I need to find the number every n numbers in this list. So I want to find the *n*th item in a list of repeating y numbers.
For example, if my list has 7 digits (y=7) and I need every 5th item (n=5), how do I find that item?
The list would be like this (which I've grouped in fives for ease of viewing):
12345 67123 45671 23456 71234 56712 34567
I need to find in the first grouping number 5, then in the second grouping number 3, then 1 from the third group, then 6, then 4, then 2, then 7.
This needs to work for any number for y and n. I usually use a modulus for finding *n*th items, but only when the list keeps increasing in number and not resetting.
I'm trying to do this in Javascript or JQuery as it's a browser based problem, but I'm not very mathematical so I'm struggling to solve it.
Thanks!
Edit: I'm looking for a mathematical solution to this ideally but I'll explain a little more about the problem, but it may just add confusion. I have a list of items in a carousel arrangement. In my example there are 7 unique items (it could be any number), but the list in real terms is actually five times that size (nothing to do with the groups of 5 above) with four sets of duplicates that I create.
To give the illusion of scrolling to infinity, the list position is reset on the 'last' page (there are two pages in this example as items 1-7 span across the 5 item wide viewport). Those groups above represent pages as there are 5 items per page in my example. The duplicates provide the padding necessary to fill in any blank spaces that may occur when moving to the next page of items (page 2 for instance starts with 6 and 7 but then would be empty if it weren't for the duplicated 1,2 and 3). When the page goes past the last page (so if we try to go to page 3) then I reposition them further back in the list to page one, but offset so it looks like they are still going forwards forever.
This is why I can't use an array index and why it would be useful to have a mathematical solution. I realise there are carousels out there that do similar tasks to what I'm trying to achieve, but I have to use the one I've got!
Just loop every 5 characters, like so:
var data = "12345671234567123456712345671234567";
var results = [];
for(var i = 4; i < data.length; i += 5){
results.push(data[i]);
}
//results = [5, 3, 1, 6, 4, 2, 7]
If you want to use a variable x = 5; then your for loop would look like this:
for(var i = x - 1; i < data.length; i += x){...
There is no need to know y
If your input sequence doesn't terminate, then outputting every nth item will eventually produce its own repeating sequence. The period (length) of this repetition will be the lowest common multiple of the period of the input sequence (y) and the step size used for outputting its items (x).
If you want to output only the first repetition, then something like this should do the trick (untested):
var sequence = "1234567";
var x = 5;
var y = sequence.length;
var count = lcm(x, y);
var offset = 4;
var output = [];
for (var i = 0; i < count; i += x)
{
j = (offset + i) % y;
output.push(sequence[j]);
}
You should be able to find an algorithm for computing the LCM of two integers fairly easily.
A purely mathematical definition? Err..
T(n) = T(n-1) + K For all n > 0.
T(1) = K // If user wants the first element in the series, you return the Kth element.
T(0) = 0 // If the user want's a non-existent element, they get 0.
Where K denotes the interval.
n denotes the desired term.
T() denotes the function that generates the list.
Lets assume we want every Kth element.
T(1) = T(0) + K = K
T(2) = T(1) + K = 2K
T(3) = T(2) + K = 3K
T(n) = nk. // This looks like a promising equation. Let's prove it:
So n is any n > 1. The next step in the equation is n+1, so we need to prove that
T(n + 1) = k(n + 1).
So let's have a go.
T(n+1) = T(N+1-1) + K.
T(n+1) = T(n) + K
Assume that T(n) = nk.
T(n+1) = nk + k
T(n+1) = k(n + 1).
And there is your proof, by induction, that T(n) = nk.
That is about as mathematical as you're gonna get on SO.
Nice simple recurrence relation that describes it quite well there.
After your edit I make another solution;)
var n = 5, y = 7;
for (var i = 1; i<=y; i++) {
var offset = ( i*y - (i-1)*n ) % y;
var result = 0;
if (offset === n) {
result = y;
} else {
result = (n - offset) > 0 ? n - offset : offset;
}
console.log(result);
}
[5, 3, 1, 6, 4, 2, 7] in output.
JSFIDDLE: http://jsfiddle.net/mcrLQ/4/
function get(x, A, B) {
var r = (x * A) % B;
return r ? r : B;
}
var A = 5;
var B = 7;
var C = [];
for (var x = 1; x <= B; ++x) {
C.push(get(x, A, B));
}
console.log(C);
Result: [5, 3, 1, 6, 4, 2, 7]
http://jsfiddle.net/xRFTD/
var data = "12345 67123 45671 23456 71234 56712 34567";
var x = 5;
var y = 7;
var results = [];
var i = x - 1; // enumeration in string starts from zero
while ( i <= data.length){
results.push(data[i]);
i = i + x + 1;// +1 for spaces ignoring
}

Categories