I want to write a function that takes array as an argument and returns how many numbers can be divided by 12. However, if array has a number higher than 111 then it should return 0;
I wrote this:
function isDivisble(array) {
let numberOfNum = 0;
for(let i=0; i < array.length; i++) {
if(array[i] % 12 == 0 && array[i] < 111) {
numberOfNum = numberOfNum + 1 ;
} else {
numberofNum = 0;
}
}
return console.log(numberOfNum);
}
let test = [12, 24, 36, 44, 55, 255];
isDivisble(test)
I realized that this code checks individually whether the current number is divisible and not higher than 111 and not globally whether the array has a number higher than 111, but I dont understand how to make a general array check.
Is writing for loop with if statement to check and then another for loop inside if statement makes it a little bit spaghetti?
You can use some to check if there is any element which is greater than 111 first.
Then you can use filter to get element that is divisible by 12.
Like this:
const isDivisible = (arr) => {
if (arr.some((e) => e > 111)) return 0;
return arr.filter((e) => e % 12 === 0).length;
};
const test = [12, 24, 36, 44, 55, 48];
console.log(isDivisible(test));
I've slightly modified your function that returns 0 if a number is greater than 111 else it checks if it is divisible by 12
function isDivisble(array) {
let count = 0;
for(let i=0; i<array.length; i++){
if(array[i] > 111){
return 0;
}else{
if(array[i] % 12 === 0){
count++
}
}
}
return count;
}
let test = [12, 24, 36, 44, 55, 255];
console.log(isDivisble(test));
The some array method will do the trick:
array.some(value => { return value > 111 }) will return true if any of its values is greater than 111.
You can also check if every array value respects a certain condition by using array.every with a similar callback:
array.every(value => { return value <= 111 }) is true only if every value in the array is lower than or equal to 111.
The best generic solution is the oene below
Logic
Filter the array for number greater that 111. If this filter returns an array with a length greater than 1 then return 0
Else filter the array for numbers divisible by 12. No need to check number is less than 111. Because if that number is greater than 111 the function might have already returned 0.
Retun the length of the above filter.
Working Fiddle
function isDivisbleGeneric(arr) {
const numberGreaterThanLimit = arr.filter((node) => node > 111);
let returnCount;
if(numberGreaterThanLimit.length > 0) {
returnCount = 0;
} else {
const divisibleBy12 = arr.filter((node) => node %12 === 0);
returnCount = divisibleBy12.length;
}
return returnCount;
}
let test = [12, 24, 36, 44, 55, 255];
const count = isDivisbleGeneric(test);
console.log(count);
One Line Solution
const isDivisbleOneLine = (arr) => arr.filter((node) => node > 111).length > 0 ? 0 : arr.filter((node) => node %12 === 0).length;
let test = [12, 24, 36, 44, 55, 255];
const count = isDivisbleOneLine(test);
console.log(count);
function isDivisble(array) {
// at the beginning, do from here
if (array.some(p=>p > 111)) {
return 0;
}
// Rest xxxxxx
}
Related
I am trying to write a simple "getRandomIndex" function to return a random and unused index number for a given array but I get "Maximum call stack size exceeded" error at let rndIdx = Math.floor(Math.random() * (arr.length - 0)) + 0;.
const arr = [81, 33, 45, 22, 97, 19, 60];
const usedIndexes = []; // I am trying to store used indexes here
function getRandomIndex() {
let rndIdx = Math.floor(Math.random() * (arr.length - 0)) + 0;
if(usedIndexes.includes(rndIdx)) {
getRandomIndex();
return;
} else {
usedIndexes.push(rndIdx);
}
return rndIdx;
}
// if the array length is more than 10, I always get "call stack size exceed" error.
for(let i = 0; i < arr.length; i++) {
// I need to use all elements in the array eventually
console.log(getRandomIndex());
}
What I am missing?
You must check that the length of the array allows for different unused numbers.
if (usedIndexes.length>=arr.length) {
return null
}
You need to return the output of getRandomIndex() rather than calling it, dumping the output, then returning nothing (which gives you undefined)
Fixed Code
const arr = [81, 33, 45, 22, 97, 19, 60];
const usedIndexes = []; // I am trying to store used indexes here
function getRandomIndex() {
let rndIdx = Math.floor(Math.random() * (arr.length - 0)) + 0;
if(usedIndexes.includes(rndIdx)) {
// used to be
// - getRandomIndex();
// - return;
return getRandomIndex();
} else {
usedIndexes.push(rndIdx);
}
return rndIdx;
}
// if the array length is more than 10, I always get "call stack size exceed" error.
for(let i = 0; i < arr.length; i++) {
// I need to use all elements in the array eventually
console.log(getRandomIndex());
}
Output
0
2
4
3
1
6
5
I was given this problem at one of my interviews and was told I have 20 minutes to solve it. This is the answer I came up with ( 2 versions ). Can you let me know which version you prefer and why, and if you have a better idea of how to solve it (less complex, less memory usage, etc.) Please share.
Problem: You have an array of random numbers that range from 0 to 100 elements.
Write a function that will split this array into several arrays, each containing elements in the following range: (0-10],(10-20],(20-30], etc up to a 100].
Write a function that outputs these arrays in a form of a simple graph, where each delimiter represents a single value in the array.
Array = [10, 12, 71, 52, 51, 1, 5, 22, 21, 6, 95, 11, 3, 64, 45, 55,
65, 42, 99, 4];
Desired outcome:
5 Elements in array: ***** - 1,5,6,3,4
3 Elements in array: *** - 10,12,11
2 Elements in array: ** - 22,21
No Elements in array.
2 Elements in array: ** - 45,42
3 Elements in array: *** - 52,51,55
2 Elements in array: ** - 64,65
1 Elements in array: * - 71
No Elements in array.
2 Elements in array: ** - 95,99
// Version 1
arr = [10, 12, 71, 52, 51, 1, 5, 22, 21, 6, 95, 11, 3, 64, 45, 55, 65, 42, 99, 4];
const splitArray = (inputArray, range) => {
const newArray = [];
do {
let tempArray = [];
tempArray = inputArray.filter((item) => {
if (item >= range && item < range + 10) return item;
});
range += 10;
newArray.push(tempArray);
} while (range + 10 <= 100);
return newArray;
};
const printArrays = (array, delimiter) => {
let toPrint = "";
for (index in array) {
let stars = array[index].length;
let string = "";
for (let i = stars; i > 0; i--) {
string += delimiter;
}
toPrint += stars
? `${stars} Elements in array: ${string} - ${array[index]} \n`
: "No Elements in array. \n";
}
return toPrint;
};
console.log(printArrays(splitArray(arr, 0), "*"));
// Version 2
arr = [10, 12, 71, 52, 51, 1, 5, 22, 21, 6, 95, 11, 3, 64, 45, 55, 65, 42, 99, 4];
const getArrays = (inputArray) => {
const newArray = [];
let min = 0;
let max = 10;
do {
const tempArray = [];
for (i in arr) {
let val = arr[i];
val >= min && val < max ? tempArray.push(val) : "";
}
min += 10;
max += 10;
newArray.push(tempArray);
} while (max <= 100);
return newArray;
};
const printArrays = (array, delimiter) => {
for (index in array) {
let stars = array[index].length;
let string = "";
for (let i = stars; i > 0; i--) {
string += delimiter;
}
console.log(
stars ? `${stars} Elements in array: ${string} - ${array[index]}` : "No Elements in array."
);
}
};
printArrays(getArrays(arr), "^");
Both approaches have moderate issues.
The first approach does
let tempArray = [];
tempArray = inputArray.filter((item) => {
if (item >= range && item < range + 10) return item;
});
Better to just declare the tempArray as the filtered array to begin with.
const tempArray = inputArray.filter(...
Also, return item is suspicious inside a filter - all the filter callback cares about is whether its return value is truthy or falsey. Returning the array item when you actually want to indicate that the value should be included in the output is a common mistake. It happens not to be a problem here because 0 isn't a possibility, but it's still confusing. A better choice would be to do
const tempArray = inputArray.filter(
item => item >= range && item < range + 10
);
(and maybe rename range to startOfRange)
Both of your approaches are also iterating through the entire input array multiple times (once for each range), which seems a bit wasteful - better to iterate through the input once.
Your second approach uses for (i in arr), and both approaches are doing for (index in array). This is a bad idea, and since you don't actually care about the index you're iterating over, it'd make sense to use for..of loops instead.
I think a better looking approach that iterates through the input just once would be:
const arr = [10, 12, 71, 52, 51, 1, 5, 22, 21, 6, 95, 11, 3, 64, 45, 55, 65, 42, 99, 4];
const getArrays = (inputArray) => {
const grouped = {};
for (let i = 0; i < 100; i += 10) {
grouped[i] = [];
}
for (const item of inputArray) {
const rangeProp = Math.floor(item / 10) * 10;
grouped[rangeProp].push(item);
}
return Object.values(grouped);
};
const printArrays = (groupedArrays, delimiter) => {
for (const array of groupedArrays) {
const stars = delimiter.repeat(array.length);
console.log(
stars
? `${array.length} Elements in array: ${stars} - ${array.join(',')}`
: "No Elements in array."
);
}
};
printArrays(getArrays(arr), "*");
I will do that this way :
This approach is simple: it retrieves the values one by one and adds them to the array corresponding to their range.
const arr = [10, 12, 71, 52, 51, 1, 5, 22, 21, 6, 95, 11, 3, 64, 45, 55, 65, 42, 99, 4];
let ranges = arr.reduce((a,x)=>
{
let range = (x/10)|0 // get range start value 0 to 9
a[range] ??= [] // create the array of if it does not already exist
a[range].push(x)
return a
},{})
console.log('ranges=', ranges ) // so that noobs can visualize this result
for (let r = 0; r < 10; r++ )
{
if (!ranges[r])
document.write('No Elements in array.<br>')
else
{
let count = ranges[r].length
document.write(`${count} Elements in array: ${'*'.repeat(count)} - ${ranges[r].join(',')}<br>`)
}
}
.as-console-wrapper {max-height: 100% !important; width:20%; top: 0;
margin-left: 80%; }
.as-console-row::after {display: none !important;}
range = (x/10)|0 // get range start value 0 to 9
example in case of x = 25 -> 25/10 give 2.5 and 2.5 | 0 give 2 -> integer part value of 2.5
| is the OR boolean operator, work only on integers values so it return an interger
??= is Logical nullish assignment
Im learning Javascipt and actually im on episode with array methods.
My imaginary exercise relies on found the Max/Min value in array by array.find method.
Acutally I did smth like that, but script returned me "Undefined".
Please help. :)
const scores = [10, 20, 30, 22, 25, 109, 90];
const maxScore = scores.find(score => {
let max = 0;
for (let i=1; i < scores.length; i++){
if(score[i] > max){
max = score[i];
};
};
return max;
});
console.log(maxScore);
P.S. I know about "Math.max.apply", but I have to do it by array.find and simple loop.
You could take a closure over an index for looping from the end and a temporary max value which is at start undefined and gets the first value from the first element.
Then loop while the value at temp index is smaller than score, store this value in max, repeat.
At the end return the result if index plus one is equal to the temp index.
This approach takes a single loop. find iterates from start of the array and the inner loop from the end of the array if both indices cross, the result is found.
const
scores = [100, 20, 30, 22, 25, 109, 90],
maxScore = scores.find(
((j, max) => (score, i, array) => {
if (max === undefined) {
max = score;
j = array.length;
}
if (score < max) return;
while (array[j - 1] < score) max = array[--j];
return i + 1 === j;
})
()
);
console.log(maxScore);
The simplest way to do it, without using any Array methods, can be written as:
const maxScore = (scores) => {
let score = 0;
for ( let i = 0; i < scores.length; i++ ) {
if(scores[i] > score) {
score = scores[i]
}
}
return score;
}
From MDN:
The find() method returns the value of the first element
in the provided array that satisfies the provided testing function.
Lets redefine our simple function again,
const maxScore = scores => {
let score = Number.NEGATIVE_INFINITY;
scores.forEach(element => {
let acc = scores.find(number => number > score);
if(!isNaN(acc)) {
score = acc;
}
})
return score;
}
find works on each array element. So take the max outside the find method & log max. Besides there were two typos
const scores = [10, 20, 30, 22, 25, 109, 90];
let max = 0;
const maxScore = scores.find((score) => {
for (let i = 1; i < scores.length; i++) {
if (scores[i] > max) {
max = scores[i];
};
};
return max;
});
console.log(max)
Try this:
const scores = [10, 20, 30, 22, 25, 109, 90];
let max = 0;
scores.find(score => { if(score > max) max = score });
console.log(max);
Your current code is looping the scores array whilst its already looping it, JavaScripts .find, essentially loops the array.
const scores = [10, 20, 30, 22, 25, 109, 90];
scores.reduce(function(a,b) { return a > b ? a : b });
// 109
I have a Javascript array which I wanted to slice and put in a new array, but the new array prints out only the last value.
I tried using for loop
let array = [5, 6, 9, 7, 10, 17, 20, 35, 105, 140];
let slicedArray;
const removeNumbers = () => {
for (let i = 0; i < array.length; i++) {
if (array[i] % 5 === 0 && array[i] % 7 === 0) {
slicedArray = [...array.splice(i, 1)];
}
}
return slicedArray;
}
console.log(removeNumbers());
I expected 35,105, and 140 as an output, but the actual output is just 140.
Use .filter instead, to create a new array based on elements of a different array that pass a test:
let array = [5, 6, 9, 7, 10, 17, 20, 35, 105, 140];
const newArr = array.filter(num => num % 5 === 0 && num % 7 === 0);
console.log(newArr);
If you have to mutate the existing array as well, then push the spliced element to the new array while splicing (don't reassign the slicedArray, just push to it):
const array = [5, 6, 9, 7, 10, 17, 20, 35, 105, 140];
const removeNumbers = () => {
const slicedArray = [];
for (let i = 0; i < array.length; i++) {
if (array[i] % 5 === 0 && array[i] % 7 === 0) {
slicedArray.push(...array.splice(i, 1));
// Need to subtract 1 from i here, so that this removed index gets iterated over again next time
i--;
}
}
return slicedArray;
}
console.log(removeNumbers());
7 is not included because it's not a multiple of 5.
Try pushing the elements in the array like this:
let array = [5,6,9,7,10,17,20,35,105,140];
let slicedArray;
const removeNumbersTest = () => {
for(let i = 0; i < array.length; i++){
if(array[i] % 5 === 0 && array[i] % 7 === 0){
slicedArray.push(...array.splice(i,1));
}
}
return slicedArray;
}
The code above should do what you wanted it to do, just check the logic before pushing the elements in the array.
Hope it helps!
You should only be getting 35, 105 and 140 according to your if statement. Since you want your numbers to bi divisible by 5 and 7.
The problem was you did not append your numbers in the array and mutated the array when using splice method. Because of mutation number 105 wasn't included.
let array = [5, 6, 9, 7, 10, 17, 20, 35, 105, 140];
let slicedArray = [];
const removeNumbers = () => {
for (let i = 0; i < array.length; i++) {
if (array[i] % 5 === 0 && array[i] % 7 === 0) {
slicedArray = [...slicedArray, ...[...array].splice(i, 1)];
}
}
return slicedArray;
}
console.log(removeNumbers());
You simply can push the target items on the slicedArray:
let array =[5,6,9,7,10,17,20,35,105,140];
const slicedArray=[]; //Array is mutable with const keyword
const removeNumbers= () =>{
for(let i=0; i<array.length; i++){
if(array[i] % 5 === 0 && array[i] % 7 === 0){
slicedArray.push(array[i]);
}
}
return slicedArray;
}
console.log(removeNumbers());
Two problems with your code and some minor issues:
array.slice() returns removed items and you have to collect them sequentially.
Solution: Push the items returned from array.slice() to the collecting array using array.push().
array.slice() modifies the array in place. Say the current index i is set to 7, that item 35 gets removed by the slicing operation from array. But now the next number 105 is shifted one position downwards. The for-loop continues with index 8 which now contains number 140.
Solution: Modify the for-loop index when an item is removed.
The naming slicedArray is misleading. Better name would be removedNumbers.
The variable removedNumbers should be a local to the function removeNumber().
Using a global variable array is not perfect. Maybe you would like to change your code to removeNumbers() takes a parameter. I omitted this fix from my example.
A fixed solution could look like:
(Please note the i-- which fixes the index to test in the next for-loop iteration the same position again.)
let array = [5,6,9,7,10,17,20,35,105,140];
const removeNumbers = () => {
let removedNumbers = [];
for(let i=0; i<array.length; i++){
if(array[i] % 5 === 0 && array[i] % 7 === 0) {
removedNumbers.push(...array.splice(i--,1));
}
}
return removedNumbers;
}
console.log("Removed numbers:", removeNumbers());
console.log("Remaining numbers:", array);
If you expect 7, 35,105, and 140 then append to the list and change your if to
if (array[i] % 7 === 0 && array[i] % 5 === 0)
Where is the mistake? I want to sum every number in the array. The alert says NaN.
var numbers = [10, 42, 5, 87, 61, 34, 99];
var i = 0;
var e = 0;
while(i <= numbers.length) {
e = e + numbers[i];
i++;
}
alert(e);
This line is the reason:
while(i <= numbers.length) {
Arrays are 0 index so you can go from index 0 (inclusive) until numbers.length (exclusive). You are going beyond that limit, causing you to access an element that isn't defined at the given index. You must do this instead:
while(i < numbers.length) {
Alternatively using the ES2015 syntax you can do it like this.
let numbers = [10, 42, 5, 87, 61, 34, 99];
let sum = numbers.reduce((a,b) => a + b);
You can read about Array.prototype.reduce(accumulator, element, callback, startingValue) here.
Your condition is wrong, just use < insteead of <=
while(i < numbers.length)
There's a few ways you can improve this. The first is that you want to change your condition to i < numbers.length, not i <= numbers.length. As you've written it, the last number will never be counted.
Another way you can improve this is using the += notation -- there's no need to write e = e + numbers[i] when you can write e += numbers[i].
You could íterate from the end of the array with a post increment and a check for truthyness in the while condition.
Inside just add the item.
var numbers = [10, 42, 5, 87, 61, 34, 99],
i = numbers.length,
e = 0;
while (i--) {
e += numbers[i];
}
console.log(e);
The problem is in array length You are checking because array index starts with 0. In that way when doing:
i <= numbers.length
You are checking [0: 10, 1: 42, 2: 5, 3: 87, 4: 61, 5: 34, 6: 99, 7:???] because numbers length is 7. To solve it just do:
i < numbers.length
where You don't check non existing number in array.
Here is how we were thought in school:
//main code//
var numbers = [10, 42, 5, 87, 61, 34, 99];
var result = sumIntArray(numbers);
//end of main code//
function sumIntArray(array){
var result = 0;
for (var i = 0; i < array.length; i++) {
if (array[i].isInteger()) {
result += array[i];
} else {
if (i === 0) {
alert("1st object in array is not number, will skip...");
}
else if (i === 1) {
alert("2nd object in array is not number, will skip...");
}
else if (i === 2){
alert("3rd object in array is not number, will skip...");
}
else {
alert((i+1).toString() + "th object in array is not number, will skip...");
}
}
}
return result;
}
The for loop adds this i++ You make in a while loop and makes code a bit more clear.
No need for declaring i in main code :)
Always make functions to simplify main code.
Make function that will never make mistake even if somebody wants to break The logic.
Although don't make school break Your creativity, Your code is great! :)