Javascript loop infinitely up till a certain condition - javascript

// Contains a list of items in each set.
var sets[0] = [1,2,3,4,5,6,7,8,9],
sets[1] = [10,11,12,13,14,15,16,17,18],
sets[2] = [19,20,21,22,23,25,26,27]
// Contains the mins associated to each set item.
var setTimes[0] = [15,15,15,15,15,15,15,15,15],
setTimes[1] = [16,12,11,15,13,15,15,15,14],
setTimes[2] = [16,12,11,15,13,12,11,15,13]
I've got a set of arrays as given above. The sets array has a data set of values. This array can have n number of items in it. Ex, sets[n].
Each sets array has an equivalent setTimes array that has minutes stored in it. setTimes[0][0] is 15min and is the number of minutes for sets[0][0].
Given a set item(ex 12), I'd like to:
Find out which set array does the given number belong to? In our case, since 12 was the item, it belongs to sets[1].
Once I have this, I'd like to get the sum of all mins from the setTimes array for the current sets index and also the next index. In our case, that would be the sum of setTimes[1] and setTimes[2].
In the event we reach the end of sets array, I'd like to get the sum of the first set array.
For ex,
- if I pass 12, I'll need to get the sum of setTimes[1] and setTimes[2]
- If I pass 23, I'll need to get the sum of setTimes[2] and setTimes[0]
Here is the loop I've been thinking, would like to know if there is a better way of doing this.
function computeTotalMin(givenItem)
{
// represents how many sets to loop thorough. I need 2.
for (x = 0; x <= 1; x++)
{
for(i = 0; i < sets.length; i++)
{
// checking to see if i value is on the last index of the sets array.
if(i === sets.length - 1)
{
i = 0;
var item = sets[i].indexOf(givenItem);
if(item !== -1)
{
// Loops through all mins from setTimes[i] array
for(j = 0; j < setTimes[i].length; j++)
{
var total = total + setTimes[j];
}
}
}
}
}
}

You don't need two nested loops for continuing at the end. You should have a single loop that iterates the number of sets you're interested in (2), and has an index (starting at the one set you've found). Inside that loop, you'd make a modulo operation on the index; to get back to the start when you've reached the end. By only looping over the count, not the (resettable) index, you won't get into an infinite loop.
You also should divide your program in just those tasks that you've textually described (find this, then do that), instead of munching everything in one huge nested control structure.
function computeTotalMin(givenItem) {
var setIndex = -1;
for (; setIndex < sets.length; setIndex++)
if (sets[setIndex].indexOf(givenItem) > -1)
break;
if (setIndex == sets.length)
return null; // givenItem found in none of the sets
var sum = 0;
for (var count = 0; count < 2; count++) {
for (var i=0; i<setTimes[setIndex].length; i++)
sum += setTimes[setIndex][i];
setIndex++; // go to next set
setIndex %= sets.length; // which might be 0
// alternatively: if (setIndex == sets.length) setIndex = 0;
}
return sum;
}

Related

Creating new array from unique elements found in array

I was given an assignment:
Finding unique elements in an array and creating a new array from these unique elements.
The professor gave us the pseudocode to code this assignment - it should be straightforward but my code is not working.
Here is my attempt:
// search for unique birthdays in the array
function find(birthdays) {
var uniqueBirthdays = [];
for (var i = 1; i <= birthdays.length; i = i + 2) {
var count = 0;
for (var j = 1; j <= birthdays.length; j = j + 2) {
if (birthdays[i] == birthdays[j]) {
count++;
}
}
if (count == 1) {
var n = uniqueBirthdays.length;
uniqueBirthdays[n] = birthdays[i - 1];
}
}
return uniqueBirthdays;
}
I have tried checking for indentation errors as well as a number of other things but can not figure out why as the array is traversed it is giving each element a count of only 1 (meaning there are no matching elements) - it does not seem to be traversing the array more than once so no elements have a count greater than 1 - even though I am using nested for loops.
I have increased the intervals by 2 because I need to compare every other element - there is a number assigned to each birthday so the array may look like:
['0001'][12/15]['0002'[03/12]...
I am brand new so I may be overlooking simple but ive tried so many things and i can not understand why this code isnt working - it is returning back all of the elements that are assigned to the birthdays instead of just the unique ones.
Any help that will point me in the right direction is very much appreciated.
You were very close, and there were just a couple mistakes. The only things that did not work were the way you wrote your for loops:
for (var i = 1; i <= birthdays.length; i = i + 2) {
Array indexes start at 0, so if you want to process the first element, use var i = 0;
Since these indexes start at 0, for an Array of 3 elements, the last index is 2. So you only want to run your loop while i is less than the array length: i < birthdays.length
You were skipping elements by doing i = i + 2. There seems to be no reason for it?
Something else worth mentionning: in JS, indentation does not matter - well, it does, but only to avoid making your eyes bleed. In fact, most websites use minified versions of their code, which fits on a single (often very long and ugly) line (example).
Here is your code, with only two lines fixed:
function find(birthdays) {
var uniqueBirthdays = [];
for (var i = 0; i < birthdays.length; i = i + 1) { // <-----
var count = 0;
for (var j = 0; j < birthdays.length; j = j + 1) { // <-----
if (birthdays[i] == birthdays[j]) {
count++;
}
}
if (count == 1) {
var n = uniqueBirthdays.length;
uniqueBirthdays[n] = birthdays[i];
}
}
return uniqueBirthdays;
}
// I used letters instead of birthdays for easier demo checking
var birthdays = ['a', 'b', 'a', 'c'];
console.log( find(birthdays) ); // ["b", "c"]
JS have direct methods tor that use Array.indexOf(), Array.lastIndexOf() and Array.filter()
uniques elements have same first position and last position
sample code:
const initailArray = [...'ldfkjlqklnmbnmykdshgmkudqjshmjfhmsdjhmjh']
const uniqueLetters = initailArray.filter((c,i,a)=>a.indexOf(c)===a.lastIndexOf(c)).sort()
console.log(JSON.stringify(uniqueLetters))

How to iterate over an array of numbers to find the first number that occurs 3 times in the array

I have the following code
let range = [1,2,3];
let multiples = [1,2,3,4,5,6,2,4,6,3,6];
I want to find the first number in the multiples array that occurs range.lenght times (3);
I want to start with multiples[0] check how many times it occurs in multiples, if it occurs 3 times I want to return multiples[0], if it is less than 3 times, I want to check how many times multiples[1] occurs in the multiples array. If multiples[1] occurs 3 times I want to return multiples[1], else I move on to check multiples[2], etc. until I find a number that occurs 3 times. In the code above I should return 6.
I've looked at
How to count the number of certain element in an array?
and
Idiomatically find the number of occurrences a given value has in an array
and
get closest number out of array
among other research but have not figured it out yet.
I tried to simplify the question as much as possible. But if more info is needed it relates to this challenge on freeCodeCamp. Where I am at with my code is
function smallestCommons(arr) {
let sortArr = arr.sort((a, b) => a - b);
console.log(sortArr);
let range = [];
for (let i = sortArr[0]; i <= sortArr[1]; i++) {
range.push(i);
}
console.log("range = " + range);
let maxNum = range.reduce( (a, b) => a * b);
console.log("maxNum = " + maxNum);
let multiples = [];
for (let i = 0; i < maxNum; i++) {
let j = 0;
do {
multiples.push(j + range[i]);
j += range[i];
} while (j < maxNum);
//j = 0;
}
for (let i = 0; i < multiples.length; i++) {
let numberToFind = multiples[i];
/*stuck here hence my question, maybe I shouldn't even start with a for loop*/
//tried reduce, forEach, filter, while loop, do while loop
}
console.log("multiples = " + multiples);
}
console.log(smallestCommons([1,3]));
The logs are
1,3
range = 1,2,3
maxNum = 6
multiples = 1,2,3,4,5,6,2,4,6,3,6,NaN,NaN,NaN
What you can do is, first split your string with , and then using below function loop for check.
function countLength(arr, checkNumber) {
var count = 0;
for (var i = 0; i < arr.length; i++) {
if (arr[i] === checkNumber) {
count++;
}
}
return count;
}
countLength(list, NUMBER YOU WANT TO CHECK);
And if you want to check first number occur for 3 time then you need to make change in function and introduce .map or .filter in action to count number.
Example
const multiples = [1,2,3,4,5,6,2,4,6,3,6];
let occurance_arr=[];
const aCount = [...new Set(multiples)].map(x => {
if(multiples.filter(y=> y==x).length == 3) {
occurance_arr.push(x);
}
});
console.log(occurance_arr);
Above code will give you 6 in console, if you have multiple value then 0th element is the answer you are looking for which is first three time occurrence of item.
You can loop through your list keeping an object that maps each number to the number of times you've seen it. You can check the counts object as you loop, so if you see a number and the count is one less than your target, you can return it. If you make it through the loop without returning you didn't find what you're looking for — return something sensible :
let range = [1,2,3]
let multiples = [1,2,3,4,5,6,2,4,6,3,6]
function findFirstMult(arr, len){
let counts = {} // to keep track of how many times you've seen something
for (let n of arr){ // loop throught the array
if (!counts[n]) counts[n] = 0 // if it's then first time you've seen n, defined that key
if (counts[n] == len - 1) return n // found it
counts[n] +=1 // otherwise increase the count
}
return undefined
}
console.log(findFirstMult(multiples, range.length))
This will require only one loop through the array in the worse case and will return early if if finds something.

javascript while loop correctly iterating but for loop with same logic is not, on array with integer values and some null values in there

Iterating through a javascript array which has some data in, and some null or not defined values also, is giving funny behaviors with a for loop, but not with a while loop. It is not returning when it should and is stuck in an infinite loop
I have investigated the outputs extensively, the condition whether the number exists in the array is never evaluated to be true, only ever false, but it sometimes enters the if statement region as if it is true. It is seemingly arbitrary.
//function called within this code
function randomArrayOfIndexes() {
var randNumbArray = new Array(4);
var indexToAssign = Math.floor(Math.random() * Math.floor(4));
randNumbArray[0] = indexToAssign;
for (i = 1; i < randNumbArray.length; i++) {
indexToAssign = Math.floor(Math.random() * Math.floor(4));
while (arrayContains(randNumbArray, indexToAssign)) {
indexToAssign = Math.floor(Math.random() * Math.floor(4));
}
randNumbArray[i] = indexToAssign;
}
return randNumbArray;
}
//this works
function arrayContains(arrayin, numberIn) {
var i = arrayin.length;
while (i--) { //takes one from i so highest index is accurate on first iteration
if (arrayin[i] === numberIn) {
return true;
}
}
return false;
}
//this doesn't... not even backwards like the above iteration
function arrayIncludes(arrayin, numberIn) {
for (i = 0; i < arrayin.length; i++) {
if (arrayin[i] === numberIn) {
return true;
}
}
return false;
}
At first each function above is passed in an array with [int value, null, null, null], and a random number; when the function returns, the next null value is filled with the random number that doesn't exist in it already, so [int value, int value, null, null]... until all values are filled... the final array is filled with unique random numbers from 0 to 3, to provide an index for a piece of data in another array... to make sure that it is only used once in the program I am writing.
I would expect it to return true if the number passed in is already in there, another random number then generated outside of the broken function, and the process repeated until a unique random number is found. When it is found, the array being passed back in will be populated at the next available index, and the process repeated. This is not happening. It is getting stuck in an infinite loop, and never returning
you are just missing a var before i:
function arrayIncludes(arrayin, numberIn) {
for (var i = 0; i < arrayin.length; i++) {
// in ^ here
if (arrayin[i] === numberIn) {
return true;
}
}
return false;
}
You may also declare it before loop, like
var i;
for (i = 0; i < arrayin.length; i++) {
...
By the way, this way of generating random numbers without duplicates is very inefficient, I suggest something like having an array of 0-3 (in your current example) or 0-n and then just randomly taking items out of it. then you don't have to loop through the whole array each time you find a new number. every time you just find a random index between 0 and the length of remaining items.
Imagine that the array length is 1000, and the last item remaining is a number like 100, how many times you have to find a random number and loop through whole array till your random number is 100?
var n = 5;
var a = new Array(n);
for(var i=0;i<n;i++) a[i] = i;
var result = new Array(n);
var i = n;
while(i)
{
var index = Math.floor(Math.random() * i);
result[--i] = a[index];
a.splice(index,1);
}
document.getElementById('a').innerHTML = result;
<div id="a"></div>
You need to declare variables in you loops with for i=0. if you don't do this the variable is global and when you use the same loop variable in nested loops one can change the other.
You are using i in both loops so when you call the for loop with:
function arrayIncludes(arrayin, numberIn) {
for (i = 0; i < arrayin.length; i++) {
// etc
}
You set i back to 0 ad iterate it — this is the same i you are using in randomArrayOfIndexes so it interferes with that loop. This is a common cause of hard-to-find bugs and is hy you should always declare loop variables.
Here's the bug in it's simplest form. Notice that the out loop only runs once because i is incremented in the inner loop causing the outloop to exit early:
for (i = 0; i < 4; i++){
console.log("out loop number: ", i)
for (i = 0; i < 4; i++){
console.log("inner_loop: ", i)
}
}
If you declare the variables for for let i =, each loop gets its own version of i both loops run independently:
for (let i = 0; i < 4; i++){
console.log("out loop number: ", i)
for (let i = 0; i < 4; i++){
console.log("inner_loop: ", i)
}
}

Algorithm: Next Greater Element I (from leetcode)

can someone please tell me what I'm missing in solving this algorithm? One problem I have is that my first if statement inside the nested loop is not evaluating, but I don't know why it wouldn't evaluate.
Here is the description of the problem:
You are given two arrays (without duplicates) nums1 and nums2 where nums1’s elements are subset of nums2. Find all the next greater numbers for nums1's elements in the corresponding places of nums2.
The Next Greater Number of a number x in nums1 is the first greater number to its right in nums2. If it does not exist, output -1 for this number.
Example 1:
Input: nums1 = [4,1,2], nums2 = [1,3,4,2].
Output: [-1,3,-1]
Explanation:
For number 4 in the first array, you cannot find the next greater number for it in the second array, so output -1.
For number 1 in the first array, the next greater number for it in the second array is 3.
For number 2 in the first array, there is no next greater number for it in the second array, so output -1.
link to original description
And here is my code so far:
var nums1 = [4,1,2];
var nums2 = [1,3,4,2];
var nextGreaterElement = function(findNums, nums) {
var holder = [];
for (var i = 0; i < findNums.length; i++) {
//loop through the 2nd array starting at the index of the first loop's current item.
for (var j = nums.indexOf(findNums[i]); i < nums.length - j; i++) {
if (nums[j+1] > nums[j]) {
holder.push(nums[j+1]);
break;
}
if (nums[nums.length]) {
holder.push(-1);
}
}
}
return holder;
};
nextGreaterElement(nums1, nums2)
Thanks for any help.
Problem: Updating variant i, but not variant j in inner loop (j-loop)
Missing: Debugging Effort
Problem Description
Theoretically, your code design should compare each value in nums1 to related parts of nums2. So, it would turn to a outer for-loop to loop on nums1 and an inner for-loop to loop related parts of nums2 for each iteration of the outer for-loop.
In your code, variant i is the index pointer for findNums (i.e. nums1) while variant j is the index pointer for nums (i.e. nums2). Variant i is always updating in both inner for-loop and outer for-loop while variant j is set once for every iteration of outer for-loop. This contradict to what you are suppose to do.
Debugging (Your Missing Work)
Find a piece of paper and a pen. Sit down, dry run the program and keep recording related info (variant i, variant j, findNums[i], nums[j], ...), you could figure out why your code is not working.
Possible Solution
var nextGreaterElement = function(findNums, nums) {
var holder = [];
for (var i = 0; i < findNums.length; i++) {
var hasNextGreaterElement = false;
// try to serach for next greater element
for (var j = nums.indexOf(findNums[i])+1; j < nums.length; j++) {
// handle case for next greater element is found
if (nums[j] > findNums[i]) {
holder.push(nums[j]);
hasNextGreaterElement = true;
break;
}
}
// handle case for next greater element is not found
if (!hasNextGreaterElement) {
holder.push(-1);
}
}
return holder;
};
var findNums=[4,1,2];
var nums=[1,3,4,2];
console.log(nextGreaterElement(findNums, nums));
You need to sort the array you are looking in to make it easier to find the number. If the array get big you might want a search algorithm to find the index in the array faster. With the array that is going to be looked in sorted you can grab the next number as the number that is one larger and check to see if you are at the end of the array. If you don't do this check the function will error when you can't find the number or when there is no number larger. Finally your second if statement didn't make sense. So I am checking to make sure that we are at the end of the array before outputting the -1 in the array.
var nextGreaterElement = function(findNums, nums) {
var holder = [];
//Should sort the array to make sure you get the next largest number
nums = nums.sort();
for (var i = 0; i < findNums.length; i++) {
//loop through the 2nd array starting at the index of the first loop's current item.
//for (var j = nums.indexOf(findNums[i]); i < nums.length - j; i++) {
for(var j = 0; j < nums.length; j++){
//check for value in array and make sure the value is not at the end
if (findNums[i] == nums[j] && j != nums.length - 1) {
holder.push(nums[j+1]);
break;
}
//check for the last element in array if so output -1
if (j == nums.length - 1) {
holder.push(-1);
}
}
}
return holder;
};

Is this the right way to iterate through an array?

Here is the code in question:
var L1 = [];
var Q1 = [];
function populateListOne() {
var limit = prompt("please enter a number you would like to fill L1 to.");
for (i = 2; i <= limit; i++) {
L1[i] = i;
}
for (n = 2; n <= L1.length; n++) {
var count = 2;
if (n == count) {
var index = L1.indexOf(n);
L1.splice(index, 1);
Q1[n] = n;
count = count + 1;
}
for (j = 0; j <= L1.length; j++) {
if (L1[j] % 2 == 0) {
var secondIndex = L1.indexOf(j);
L1.splice(secondIndex, 1);
}
}
}
document.getElementById("demo").innerHTML = "iteration " + "1" + ": " + L1 + " Q1 = " + Q1;
}
I’m currently working on a homework assignment where I have to setup a queue. All is explained in my JSFiddle.
Problem description
Essentially, the part I’m stuck on is iterating through each instance of the array and then taking the value out if the modulus is identical to 0. However, as you can see when I run the program, it doesn’t work out that way. I know the problem is in the second for loop I just don’t see what I’m doing wrong.
The way I read it is, if j is less than the length of the array, increment. Then, if the value of the index of L1[j] modulus 2 is identical to 0, set the value of secondIndex to whatever the index of j is. Then splice it out. So, theoretically, only numbers divisible by two should be removed.
Input
A single number limit, which will be used to fill array L1.
L1 will be initialized with values 2, 3, ... limit.
Process
Get the starting element of array L1 and place it in array Q1.
Using that element, remove all values in array L1 that are divisible by that number.
Repeat until array L1 is empty.
You're going to have issues with looping over an array if you're changing the array within the loop. To help with this, I tend to iterate from back to front (also note: iterate from array.length - 1 as the length element does not exist, arrays are key'd from 0):
for(j = L1.length - 1; j >=0 ; j--)
For your first loop, you miss the elements L1[0] and L1[1], so I would change the first loop to:
L1 = [];
for(i = 2; i <= limit; i++)
{
L1.push(i);
}
In this section:
for(j = 0; j <= L1.length; j++){
if(L1[j] % 2 == 0)
{
var secondIndex = L1.indexOf(j);
L1.splice(secondIndex, 1);
}
}
you should splice with j instead of secondIndex.
Change L1.splice(secondIndex, 1); to L1.splice(j, 1);
Array indices and putting entries
You initial code used an array that was initialized to start at index 2. To avoid confusion, of what index to start at, start with index 0 and iterate until array.length instead of a predefined value limit to ensure that you go through each element.
The following still works but will be more of a headache because you need remember where to start and when you will end.
for (i = 2; i <= limit; i++) {
L1[i] = i; // 'i' will begin at two!
}
Here's a better way:
for (i = 2; i <= limit; i++) {
// 'i' starts at 2 and since L1 is an empty array,
// pushing elements into it will start index at 0!
L1.push(i);
}
Use pop and slice when getting values
When you need to take a peek at what value is at the start of your array, you can do so by using L1[0] if you followed my advice above regarding array keys.
However, when you are sure about needing to remove the starting element of the array, use Array.slice(idx, amt). idx specifies which index to start at, and amt specifies how many elements to remove beginning at that index (inclusive).
// Go to 1st element in L1. Remove (1 element at index 0) from L1.
var current = L1.splice(0, 1);
Use the appropriate loops
To make your life easier, use the appropriate loops when necessary. For loops are used when you know exactly how many times you will iterate. Use while loops when you are expecting an event.
In your case, 'repeat until L1 is empty' directly translates to:
do {
// divisibility checking
} while (L1.length > 0);
JSFiddle
Here's a complete JS fiddle with in-line comments that does exactly what you said.

Categories

Resources