JS Breaking out of nested for loop - javascript

writing code for the following algorithmic problem and no idea why it's not working. Following a debugger, I found that the elem variable never iterates beyond 's'. I'm concerned that this could be because of my understanding of how to break out of a parent for loop. I read
this question: Best way to break from nested loops in Javascript? but I'm not sure if perhaps I'm doing something wrong.
function firstNonRepeatingLetter(s) {
//input string
//return first character that doesn't repeat anywhere else.
//parent for loop points to the char we are analyzing
//child for loop iterates over the remainder of the string
//if child for loop doesnt find a repeat, return the char, else break out of the child for loop and cont
if (s.length == 1) { return s;}
parent_loop:
for (var i = 0; i < s.length - 1; i++){ //parent loop
var elem = s[i];
child_loop:
for (var j = i + 1; j < s.length; j++){
if (elem == s[j]){
break child_loop;
}
}
return s[i];
}
return "";
}
console.log(firstNonRepeatingLetter('stress')); // should output t, getting s.

My suggestion would be to use single for loop instead of using two loops.
for( var i = 0; i<s.length - 1;i++) {
var lastIndex = s.lastIndexOf(s[i]);
if ( lastIndex == i) {
return s[i];
}
}

try with this.
this was the key of my code
if( f!=true)
return s[i];
see the full code
function firstNonRepeatingLetter(s) {
//input string
//return first character that doesn't repeat anywhere else.
//parent for loop points to the char we are analyzing
//child for loop iterates over the remainder of the string
//if child for loop doesnt find a repeat, return the char, else break out of the child for loop and cont
if (s.length == 1) { return s;}
for (var i = 0; i < s.length - 1; i++){ //parent loop
var elem = s[i];
var f=false;
for (var j = i + 1; j < s.length; j++){
if (elem == s[j]){
f=true;
break;
}
}
if( f!=true)
return s[i];
}
return "";
}
console.log(firstNonRepeatingLetter('stress')); // should output t, getting s.

I think you are breaking out the loop correctly, the reason why the function always return s is because the counter i never increments.
Let's run through the code
i = 0, element = 's', j = 1, s[j] = 't', which is not equal to 's'
j++, j = 2, s[j] = 'r', not equal to 's'
j++, j = 3, s[j] = 'e', not equal to 's'
j++, j = 4, s[j] = 's', equal to 's'
so you break out of the child loop.
Now we hit the line return s[i], when i = 0, so naturally the function returns s.
If you change the return s[i] to include an if statement, like so
if(j == s.length) {
return s[i];
}
The function now returns 't'. You are checking to see if the child loop ran to its full completion, which means break child_loop; never ran, and you have an unique letter.

Related

SOLVED: outer and inner loop were using same variable (i). Original Question: JavaScript for-loop loops only once when comparing i to an array element

Full code at: https://jsbin.com/sikeqizoda/1/edit?js,console
and the problem loop has a /**************.....*/ before and after it.
I'm doing one of the projects on freeCodeCamp and I'm encountering an issue where I have this for-loop:
for (let i = 0; i < arr[i]; i++) {
newArr.push("M");
}
in which I'm comparing an array element, in this case, arr[i] = 3, with typeof being number, and where i also has typeof = number. Again, in this situation, arr[i] = 3, and if I run the code as above, it's supposed to loop 3 times, but only loops once (only one "M" is pushed into my newArr array).
But, if I put the number 3 in place of arr[i]:
for (let i = 0; i < 3; i++) {
newArr.push("M");
}
it loops 3 times as I want it to.
I have tried putting a console.log(arr[i]) underneath there and it logs 3.
console.log(i) logs 0.
and newArr becomes ['M'].
I've also tried changing arr[i] to parseInt(arr[i]), and console.log(parseInt(arr[i]) == 3) returns true! It's so confusing, why does '3' work, but arr[i] which is equivalent doesn't?
I don't understand what the issue is. Could someone please help?
Thanks for your time.
The issue is because you've got your outer while loop iterating over i, then you declare multiple inner loops, also iterating over i, and the two are conflicting. Always use different variables for nested loops:
let one = { 0: "I", 1: "X", 2: "C", 3: "M" }
let four = { 0: "IV", 1: "XL", 2: "CD" }
let five = { 0: "V", 1: "L", 2: "D" }
let nine = { 0: "IX", 1: "XC", 2: "CM" }
function consecutiveZerosAfter(index, arr) {
let numZeros = 0;
for (let i = index + 1; i < arr.length; i++) {
if (arr[i] == 0) {
numZeros += 1;
} else {
return numZeros
}
}
return numZeros
}
function arrayToRoman(arr) {
let newArr = [];
let counter = 0;
let i = 0;
while (i < arr.length) {
if (arr[i] == 0) {
i++;
} else {
if (arr[i] >= 1 && arr[i] <= 3) {
switch (consecutiveZerosAfter(i, arr)) {
case 0:
for (let n = 0; n < arr[i]; n++) {
newArr.push("I");
}
break;
case 1:
for (let n = 0; n < arr[i]; n++) {
newArr.push("X");
}
break;
case 2:
for (let n = 0; n < arr[i]; n++) {
newArr.push("C");
}
break;
/****************************************************************************************/
case 3:
for (let n = 0; n < arr[i]; n++) {
newArr.push("M");
}
break;
/***************************************************************************************/
}
} else if (arr[i] == 4) {
} else if (arr[i] >= 5 && arr[i] <= 8) {
} else if (arr[i] == 9) {
}
}
i++;
}
return newArr
}
console.log(arrayToRoman([3, 0, 0, 0]));
TLDR;
Correct code:
for (let j = 0; j < arr[i]; j++) {
newArr.push("M");
}
Long answer:
The issue is that in the for loop you are using the variable named "i" and you access the element of the array with the same variable.
When you do let i = 0 the value of the "i" variable is going to be 0, so on the first iteration of the loop you will access arr[0], and it will provide an other solution.
The answer is to use other variable name in the for loop like "j" as showed in the short answer.
The variable of the loop will be a local variable, so you can't access it from outside of the loop, so if you use "j" as the loop variables for all cases than itt will be fine.
The issue is that the variable that you are defining in for-loop (let i=0) is shadowing the variable of parent, you may want to give different name to the variable to resolve the issue.
As others have suggested, ideally you should different variables for each of the nested loops as that would make your code easier to reason with. BUT, in your case, if you really wanted you could avoid the issue by doing something like this ->
const current = arr[i];
for (let i = 0; i < current; i++) {
newArr.push("M");
}
This is just to clearly demonstrate the actual issue with your code, actual implementation should still try to use a different variable like j

How do I utilize the length of an array in a function (in JavaScript) when the array is being passed as a parameter and the length does not exist yet?

I'm trying to write a function that takes an array of strings(strarr) and an integer(k) as parameters and returns the longest string made up of k amount of consecutive strings within the array, not separated by commas. I need to call on strarr.length quite often during the function, but I keep getting an error saying that it cannot read that parameter's length.
This is my first time dealing with this issue and I have not found great internet search results for solutions. I suspect that I'm missing something very obvious. I have tried pushing the values of the strarr array parameter into a new array and still no luck.
So if I had const = ['apple','pineapple','banana','strawberry'] passed as my strarr parameter and 2 passed as k, then it should return 'bananastrawberry' because it is the longest consecutive pair of strings within the array.
const arr = ['apple', 'pineapple', 'banana', 'strawberry']
function longestConsec(strarr, k) {
if (strarr.length === 0) {
return "";
} else if (k > strarr.length) {
return "";
} else if (k <= 0) {
return "";
}
let longest = "";
let strLeng = 0;
for (let i = 0; i < strarr.length; i++) {
for (let j = i + (k - 1); j > 0; j--) {
strLeng += strarr[j].length;
}
if (strLeng > longest.length) {
longest = strarr.slice(i, (i + k)).join("");
}
}
return longest;
}
console.log(longestConsec(arr, 2))
As mentioned, you are trying to access an index that doesn't exist in you array.
A quick fix might be:
const arr = ['apple', 'pineapple', 'banana', 'strawberry']
function longestConsec(strarr, k) {
if (strarr.length === 0) {
return "";
} else if (k > strarr.length) {
return "";
} else if (k <= 0) {
return "";
}
let longest = "";
let strLeng = 0;
for (let i = 0; i < strarr.length; i++) {
for (let j = i + (k - 1); j > 0; j--) {
if (j >= strarr.length) {
break;
}
strLeng += strarr[j].length;
}
if (strLeng > longest.length) {
longest = strarr.slice(i, (i + k)).join("");
}
}
return longest;
}
console.log(longestConsec(arr, 2))
But I would suggest to see if there is better solution than adding a break statement.
Mistakes you did
In the inner for loop, for (let j = i + (k - 1); j > 0; j--), you're counting from i + k - 1. But what if i is the last index of array (strarr.length == 10 and i == 9) and k == 2? Then your loop starts at j = 9 + 2 - 1 = 10 and one line below, you try to do strLeng += strarr[10].length, but strarr[10] is not defined.
It also seems unnecessary to create strings before you're done finding the longest one. You could instead just remember start index of your last longest string instead.
How to make it better
Let's look at the requirements. For each i in the array, you want to merge k consecutive strings and keep the longest combination. From that follows:
i + k - 1 must never be larger than strarr.length. Since the i is the only variable here, we need to limit it by only looping up to strarr.length - k + 1.
If k == strarr.length, there is only one string you can make - strarr.join("")
Finally, there's an idea that you probably do not need nested loop at all. For every i, you simply subtract the length of the last string in your current window and add a new one. See image:
So with that in mind, I would propose following version of your code:
function longestConsec(strarr, k) {
// Cannot create any joined string with k greater than length
if(strarr.length < k) {
return "";
}
else if(k <= 0) {
return "";
}
else if(strarr.length == k) {
return strarr.join("");
}
let longestIndex = -1;
let longestLength = 0;
// length of our current group of strings
let currentLength = 0;
const maxLen = strarr.length;
for(let i=0; i<maxLen; ++i) {
// Forget the first strings length
if(i >= k) {
currentLength -= strarr[i-k].length;
}
// add the current strings length
currentLength += strarr[i].length;
// check if this is the largest length and save it's index
// Only possible after processing at least k strings
// Eg when i==1, we already went through 2 strings at this point
if(i >= k-1) {
if(currentLength > longestLength) {
const startIndex = i-k+1;
longestLength = currentLength;
longestIndex = startIndex;
}
}
}
return strarr.slice(longestIndex, (longestIndex + k)).join("");
}
Here's a jsFiddle test: https://jsfiddle.net/32g5oqd1/2/

getting javascript error while iterating through array

function sortproducts(filprodlist)
{
var prod;
var k = 0;
for (i = 0; i < filprodlist.length; i++) {
var k = i + 1;
var p=filprodlist[i].EntityKey.substr(filprodlist[i].EntityKey.length - 1);
var p2=filprodlist[k].EntityKey.substr(filprodlist[k].EntityKey.length - 1);
if ( p>p2) {
temp = filprodlist[k];
filprodlist[k] = filprodlist[i];
filprodlist[i] = temp;
}
}
rederProduct(filprodlist);
}
while executing above code getting following error
TypeError: filprodlist[k] is undefined
Reason
On last iteration, when i is at last element of array. You are fetching are using var k = i + 1;, where k doesn't exists. Thus you are getting the error.
So Use
for (i = 0; i < filprodlist.length - 1; i++) {
instead of
for (i = 0; i < filprodlist.length; i++) {
Don't var inside loops, blocks don't have scope in JavaScript, var every variable you want to use in one var statement. End your loop when the highest index reaches the end (k). You can move k into the for's iterate step because you're really iterating with this, too.
function sortproducts(filprodlist) {
var prod, i, k, p, p2, temp;
for (i = 0, k = 1; k < filprodlist.length; ++i, ++k) {
p = filprodlist[i].EntityKey.substr(filprodlist[i].EntityKey.length - 1);
p2 = filprodlist[k].EntityKey.substr(filprodlist[k].EntityKey.length - 1);
if (p > p2) {
temp = filprodlist[k];
filprodlist[k] = filprodlist[i];
filprodlist[i] = temp;
}
}
rederProduct(filprodlist);
}
A different way to do it is forget k all together, start from i = 1 and use i - 1 and i, this means you're iterating with less variables so it might be easier for you to follow the code in your mind.
Let's say filprodlist has 10 items. Then the items are indexed 0-9 and Your i goes through 0-9. In every iteration You define k = i + 1. So in the last iteration i = 9, k = 10 and You are trying to access filprodlist[10] which doesn't exist (returns undefined). Solution is in #Satpal's answer.

First non-negative element in an array

Hi I have an array that looks like:
hrarray = [-9,-7,0,3,7,8]
I've been trying to work out a function that selects the first non-negative (inc. 0) number in the array and returns the index (var elemid):
for (var i = 0, len=hrArray.length; i<len; i++) {
var num = hrArray[i];
if(num > 0) {
var elemid = i; //returns first non-negative element index
}
else if(num < 0) {}
Is my code logic correct?
I don't see you returning anything.
You can get the first non-negative with a single line:
for (var i = 0, len = arr.length; i < len && arr[i] < 0; i++);
Basically, we place the check for negatives in the for-loop guard. It will break once it finds a non-negative and hence return i of that first non-negative.
Update #1 (to use in a function):
function getFirstNonNegative(arr) {
for (var i = 0, len = arr.length; i < len && arr[i] < 0; i++);
// Use a ternary operator
return (i === len) ? -1 : i; // If i === len then the entire array is negative
}
Your code will assign to elemid the last non-negative in the array. Try this:
var elemid=-1; // elemid should be declared outside the for statement
for (var i = 0, len=hrArray.length; i<len; i++) {
if(hrArray[i] > 0) {
elemid = i; //returns first non-negative element index
break;
}
}
The main problem I see is that you're not breaking out of the loop once you find a non-negative value. This can be done with a break statement, or if you want to exit a function immediately, a return statement.
The function should look a bit like this:
function findNonNegative(arry) {
for (var i = 0, len = arry.length; i < len; i++) {
if(arry[i] >= 0)
return i;
}
return -1;
}
Note that this method returns -1 if no non-negative elements are found.
And with a little tweaking, this can be shortened to:
function findNonNegative(arry) {
for (var i = 0; arry[i] < 0; i++);
return i < arry.length ? i : -1;
}
This version takes advantage of the behavior of the for loop to both test our values inside the loop and break out once a desired value is found. It also depends on the fact that x < y always returns false if x is undefined, thus ensuring we do not end up with an infinite loop. The last conditional expression is there to make the return value equal -1 if no non-negative elements were found; that can be reduced to just return i; if you are okay with the return value being arry.length in that case.

Code to display all prime numbers not working in JavaScript?

I'm trying to display all the prime numbers up to 10 and it isn't working. Can you see what I did wrong?
function findPrimeNumbers() {
var count = 10,
primes = [];
for (var i = 0; i <= count; i++) {
if (count / i === 1 || count) primes.push(i);
else continue;
count -= 1;
}
for (var i = 0, len = primes.length; i < len; i++) return primes[i];
}
console.log(findPrimeNumbers());
It only returns 0 in the console.
Here's about the simplest way to generate primes. Note that there are more efficient methods, but they are harder to understand.
function findPrimeNumbers (count) {
var primes = [];
for (var J = 2; J <= count; J++) {
var possPrime = true;
for (var K = 2, factorLim = Math.sqrt (J); K <= factorLim; K++) {
if (J % K == 0) {
possPrime = false;
break;
}
}
if (possPrime)
primes.push (J);
}
return primes;
}
console.log (findPrimeNumbers (10) );
This yields all the primes <= 10:
[2, 3, 5, 7]
See Wikipedia for an explanation.
for (var i = 0, len = primes.length; i < len; i++) return primes[i];
Here you are return just the first element of the array. I think you meant something like this
var retstr = "";
for (var i = 0, len = primes.length; i < len; i++)
{
//To improve str format
if(i == len-1)
retstr += primes[i];
else
retstr += primes[i] + ", ";
}
return retstr;
Hope this helps.
if (count / i === 1 || count / i === count)
You don't say how it's not working, but the first thing that comes to my attention is that you're incrementing i, while at the same time decrementing count, so i will never get all the way to 10.
Also, count / i will cause a divide-by-zero error on the first iteration as it's written (unless Javascript magically handles that case in some way I'm not familiar with).
Then you "loop" through your return values--but you can only return once from a function, so of course you're only going to return the first value.
And you are returning from the function in the last for loop. Remove that for loop, just return the array.
function PrimeCheck(n){ //function to check prime number
for(i=2;i<n;i++){
if(n%i==0){
return false
}
}
return true;
}
function print(x){ //function to print prime numbers
var primeArray=[];
for(j=2;j<x;j++){
if(PrimeCheck(j)==true){
primeArray.push(j);
}
}
console.log(primeArray);
}
print(10); //[2,3,5,7]

Categories

Resources