Sum of range of numbers in an array(callback function) - javascript

What is wrong with this code?
function range(start, end){
var arrayRange = [];
for(i= start; i<=end; i++){
arrayRange.push(i)
}
return(arrayRange);
}
var r = range(1,10);
console.log(r);
function sumRange(sumArray){
var total = 0;
for(var i=0; i <= sumArray.length; i++){
total = total + sumArray[i];
}
return total;
}
var s=sumRange(r);
console.log(s);
This is what gets displayed in console.
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
NaN
I'm trying an exercise from Eloquent Javascript to understand callback function. My aim is to produce this
console.log(sum(range(1,10)));
// 55

The problem is i <= sumArray.length, the array indexes are from 0 to length -1 so the loop condition should be i < sumArray.length
In your case the last iteration of the loop will be total + undefined which will return NaN
function sumRange(sumArray) {
var total = 0;
for (var i = 0; i < sumArray.length; i++) {
total = total + sumArray[i];
}
return total;
}
You can use Array.reduce() like
function sumRange(sumArray) {
return sumArray.reduce(function (sum, val) {
return sum + val;
}, 0);
}

In this part of the sum function:
for(var i=0; i <= sumArray.length; i++){
total = total + sumArray[i];
}
Because your condition is i <= sumArray.length instead of i < sumArray.length, you try to access an array index that has not been set. When you do this, JavaScript will yield undefined as the value, and undefined when added to any number, will produce NaN.
The NaN value is basically JavaScript's way of letting you know that something went wrong in the calculations, without actually being helpful enough to tell you where it went wrong. Even strict mode will not modify this behavior, so you just have to be careful when you work with arrays to avoid accessing undefined keys. By the way, the same behavior exists when you try to access undefined object keys (In JavaScript, arrays are just special cases of objects).
Recall that JavaScript's arrays are zero-indexed, i.e. an array with n elements will have index keys 0..n-1, so you want to iterate up to the array's length non-inclusively using the condition
i < sumArray.length. As soon as this condition is false, you want to stop the iteration because you're in undefined territory.

Related

I need to create a function in javascript to show how many members of array are less than a given number

I think that my error is in the return section
I've tried many things but I can't find the solution
the question is : "Write a function called countNums that gets two arguments - an array of numbers and some member
And prints to the screen some organs in an array that are smaller than the given organ.
For the screen, countNums([7,3,9,1,20], 10) will be printed to read: for example
"4 elements are less than 10."
function countNums(arr, element) {
for (var i = 0; i < arr.length; i++) {
if (arr[i] < element) {
return " " + arr[i] + "elements are less than" + element + " ";
}
}
}
arr = [14, 25, 36, 50]
document.write(countNums(arr, 20));
Javascript has functions that can help you do this easily, such as array.filter which will return a subset of an array depending upon the condition.
However, I've presented an answer that uses the logic you outlined in your own attempt but modified in order to return the correct result.
The primary problem with your code was that you were not actually counting the number of elements below the target number - instead you returned when the first array element was below the target number.
I've fixed that by adding a count variable to keep a running count.
In the if statement, if the array element is lower than the number then count is incremented by one. At the end of the function, the total running count is returned.
Here's a working snippet showing this:
function countNums(arr, element)
{
let count = 0;
for (var i = 0; i < arr.length; i++) {
if (arr[i] < element)
count++;
}
return count;
}
let arr = [14,25,36,50]
let num = 20;
let result = countNums(arr, num);
document.write(result + " element(s) are less than " + num);
In the snippet above, you can modify num to specify the target number that the array elements must be lower than. The output statement will be modified automatically to show the correct wording.
It's a typical situation to use Array built-in method "reduce":
const array = [12, 6, 11, 4]
const count = (arr, num) => {
return `${arr.reduce(
(acc, val) => val < num
? acc + 1
: acc, 0
)} number(s) are less than ${num}`
}
console.log(count(array, 10))

Minimum number of swaps to sort an array

I need to do something like this: Let's say I have an array:
[3, 4, 1, 2]
I need to swap 3 and 4, and 1 and 2, so my array looks like [4, 3, 2, 1]. Now, I can just do the sort(). Here I need to count how many iterations I need, to change the initial array to the final output. Example:
// I can sort one pair per iteration
let array = [3, 4, 1, 2, 5]
let counter = 0;
//swap 3 and 4
counter++;
// swap 1 and 2
counter++;
// 5 goes to first place
counter++
// now counter = 3 <-- what I need
EDIT: Here is what I tried. doesn't work always tho... it is from this question: Bubble sort algorithm JavaScript
let counter = 0;
let swapped;
do {
swapped = false;
for (var i = 0; i < array.length - 1; i++) {
if (array[i] < array[i + 1]) {
const temp = array[i];
array[i] = array[i + 1];
array[i + 1] = temp;
swapped = true;
counter++;
}
}
} while (swapped);
EDIT: It is not correct all the time because I can swap places from last to first, for example. Look at the example code above, it is edited now.
This is most optimal code I have tried so far, also the code is accepted as optimal
answer by hackerrank :
function minimumSwaps(arr) {
var arrLength = arr.length;
// create two new Arrays
// one record value and key separately
// second to keep visited node count (default set false to all)
var newArr = [];
var newArrVisited = [];
for (let i = 0; i < arrLength; i++) {
newArr[i]= [];
newArr[i].value = arr[i];
newArr[i].key = i;
newArrVisited[i] = false;
}
// sort new array by value
newArr.sort(function (a, b) {
return a.value - b.value;
})
var swp = 0;
for (let i = 0; i < arrLength; i++) {
// check if already visited or swapped
if (newArr[i].key == i || newArrVisited[i]) {
continue;
}
var cycle = 0;
var j = i;
while (!newArrVisited[j]) {
// mark as visited
newArrVisited[j] = true;
j = newArr[j].key; //assign next key
cycle++;
}
if (cycle > 0) {
swp += (cycle > 1) ? cycle - 1 : cycle;
}
}
return swp;
}
reference
//You are given an unordered array consisting of consecutive integers [1, 2, 3, ..., n] without any duplicates.
//still not the best
function minimumSwaps(arr) {
let count = 0;
for(let i =0; i< arr.length; i++){
if(arr[i]!=i+1){
let temp = arr[i];
arr[arr.indexOf(i+1)] =temp;
arr[i] = i+1;
count =count+1;
}
}
return count;
}
I assume there are two reasons you're wanting to measure how many iterations a sort takes. So I will supply you with some theory (if the mathematics is too dense, don't worry about it), then some practical application.
There are many sort algorithms, some of them have a predicable number of iterations based on the number of items you are sorting, some of them are luck of the draw simply based on the order of the items to be sorted and which item how you select what is called a pivot. So if optimisation is very important to you, then you'll want to select the right algorithm for the purpose of the sort algorithm. Otherwise go for a general purpose algorithm.
Here are most popular sorting algorithms for the purpose of learning, and each of them have least, worst and average running-cases. Heapsort, Radix and binary-sort are worth looking at if this is more than just an theoretical/learning exercise.
Quicksort
Worst Case: Θ(n 2)
Best case: Θ(n lg n)
Average case: Θ(n lg n)
Here is a Quicksort implementation by Charles Stover
Merge sort
Worst case: Θ(n lg n)
Best case: Θ(n lg n)
Average Case: Θ(n lg n)
(note they're all the same)
Here is a merge sort implementation by Alex Kondov
Insertion sort
Worst case: Θ(n2)
Best case: Θ(n)
Average case:Θ(n2)
(Note that its worst and average case are the same, but its best case is the best of any algorithm)
Here is an insertion sort implementation by Kyle Jensen
Selection sort
Worst case: Θ(n2)
Best case: Θ(n2)
Average case: Θ(n2)
(note they're all the same, like a merge sort).
Here is a selection sort algorithm written by #dbdavid updated by myself for ES6
You can quite easily add an iterator variable to any of these examples to count the number of swaps they make, and play around with them to see which algorithms work best in which circumstance.
If there's a very good chance the items will already be well sorted, insertion sort is your best choice. If you have absolutely no idea, of the four basic sorting algorithms quicksort is your best choice.
function minimumSwaps(arr) {
var counter = 0;
for (var i = arr.length; i > 0; i--) {
var minval = Math.min(...arr); console.log("before", arr);
var minIndex = arr.indexOf(minval);
if (minval != = arr[0]) {
var temp = arr[0];
arr[0] = arr[minIndex];
arr[minIndex] = temp; console.log("after", arr);
arr.splice(0, 1);
counter++;
}
else {
arr.splice(0, 1); console.log("in else case")
}
} return counter;
}
This is how I call my swap function:
minimumSwaps([3, 7, 6, 9, 1, 8, 4, 10, 2, 5]);
It works with Selection Sort. Logic is as follows:
Loop through the array length
Find the minimum element in the array and then swap with the First element in the array, if the 0th Index doesn't have the minimum value founded out.
Now remove the first element.
If step 2 is not present, remove the first element(which is the minimum value present already)
increase counter when we swap the values.
Return the counter value after the for Loop.
It works for all values.
However, it fails due to a timeout for values around 50,000.
The solution to this problem is not very intuitive unless you are already somewhat familiar with computer science or real math wiz, but it all comes down to the number of inversions and the resulting cycles
If you are new to computer science I recommend the following resources to supplement this solution:
GeeksforGeeks Article
Informal Proof Explanation
Graph Theory Explanation
If we define an inversion as:
arr[i]>arr[j]
where "i" is the current index and "j" is the following index --
if there are no inversions the array is already in order and requires no sorting.
For Example:
[1,2,3,4,5]
So the number of swaps is related to the number of inversions, but not directly because each inversion can lead to a series of swaps (as opposed to a singular swap EX: [3,1,2]).
So if one consider's the following array:
[4,5,2,1,3,6,10,9,7,8]
This array is composed of three cycles.
Cycle One- 4,1,3 (Two Swaps)
Cycle Two- 5,2 (One Swap)
Cycle Three- 6 (0 Swaps)
Cycle Four- 10,9,7,8 (3 Swaps)
Now here's where the CS and Math magic really kicks in: each cycle will only require one pass through to properly sort it, and this is always going to be true.
So another way to say this would be-- the minimum number of swaps to sort any cycle is the number of element in that cycle minus one, or more explicitly:
minimum swaps = (cycle length - 1)
So if we sum the minimum swaps from each cycle, that sum will equal the minimum number of swaps for the original array.
Here is my attempt to explain WHY this algorithm works:
If we consider that any sequential set of numbers is just a section of a number line, then any set starting at zero should be equal to its own index should the set be expressed as a Javascript array. This idea becomes the criteria to programmatically determined if in element is already in the correct position based on its own value.
If the current value is not equal to its own index then the program should detect a cycle start and recording its length. Once the while loop reaches the the original value in the cycle it will add the minimum number of swaps in the cycle to a counter variable.
Anyway here is my code-- it is very verbose but should work:
export const minimumSwaps = (arr) => {
//This function returns the lowest value
//from the provided array.
//If one subtracts this value the from
//any value in the array it should equal
//that value's index.
const shift = (function findLowest(arr){
let lowest=arr[0];
arr.forEach((val,i)=>{
if(val<lowest){
lowest=val;
}
})
return lowest;
})(arr);
//Declare a counter variable
//to keep track of the swaps.
let swaps = 0;
//This function returns an array equal
//in size to the original array provided.
//However, this array is composed of
//boolean values with a value of false.
const visited = (function boolArray(n){
const arr=[];
for(let i = 0; i<n;i++){
arr.push(false);
}
return arr;
})(arr.length);
//Iterate through each element of the
//of the provided array.
arr.forEach((val, i) => {
//If the current value being assessed minus
//the lowest value in the original array
//is not equal to the current loop index,
//or, if the corresponding index in
//the visited array is equal to true,
//then the value is already sorted
if (val - shift === i || visited[i]) return;
//Declare a counter variable to record
//cycle length.
let cycleLength = 0;
//Declare a variable for to use for the
//while loop below, one should start with
//the current loop index
let x = i;
//While the corresponding value in the
//corresponding index in the visited array
//is equal to false, then we
while (!visited[x]) {
//Set the value of the current
//corresponding index to true
visited[x] = true;
//Reset the x iteration variable to
//the next potential value in the cycle
x = arr[x] - shift;
//Add one to the cycle length variable
cycleLength++;
};
//Add the minimum number of swaps to
//the swaps counter variable, which
//is equal to the cycle length minus one
swaps += cycleLength - 1;
});
return swaps
}
This solution is simple and fast.
function minimumSwaps(arr) {
let minSwaps = 0;
for (let i = 0; i < arr.length; i++) {
// at this position what is the right number to be here
// for example at position 0 should be 1
// add 1 to i if array starts with 1 (1->n)
const right = i+1;
// is current position does not have the right number
if (arr[i] !== right) {
// find the index of the right number in the array
// only look from the current position up passing i to indexOf
const rightIdx = arr.indexOf(right, i);
// replace the other position with this position value
arr[rightIdx] = arr[i];
// replace this position with the right number
arr[i] = right;
// increment the swap count since a swap was done
++minSwaps;
}
}
return minSwaps;
}
Here is my solution, but it timeouts 3 test cases with very large inputs. With smaller inputs, it works and does not terminate due to timeout.
function minimumSwaps(arr) {
let swaps = 0;
for (let i = 0; i < arr.length; i++) {
if (arr[i] === i + 1) continue;
arr.splice(i, 1, arr.splice(arr.indexOf(i + 1), 1, arr[i])[0]); //swap
swaps++;
}
return swaps;
}
I'm learning how to make it more performant, any help is welcome.
This is my solution to the Main Swaps 2 problem in JavaScript. It passed all the test cases. I hope someone finds it useful.
//this function calls the mainSwaps function..
function minimumSwaps(arr){
let swaps = 0;
for (var i = 0; i < arr.length; i++){
var current = arr[i];
var targetIndex = i + 1;
if (current != targetIndex){
swaps += mainSwaps(arr, i);
}
}
return swaps;
}
//this function is called by the minimumSwaps function
function mainSwaps(arr, index){
let swapCount = 0;
let currentElement = arr[index];
let targetIndex = currentElement - 1;
let targetElement = arr[currentElement - 1];
while (currentElement != targetElement){
//swap the elements
arr[index] = targetElement;
arr[currentElement - 1] = currentElement;
//increase the swapcount
swapCount++;
//store the currentElement, targetElement with their new values..
currentElement = arr[index];
targetElement = arr[currentElement - 1];
}
return swapCount;
}
var myarray = [2,3,4,1,5];
var result = console.log(minimumSwaps(myarray));
you can also do it with a map. But its O(nlogn)
const minSwaps = (arr) =>{
let arrSorted = [...arr].sort((a,b)=>a-b);
let indexMap = new Map();
// fill the indexes
for(let i=0; i<arr.length; i++){
indexMap.set(arr[i],i);
}
let count = 0;
for(let i=0; i<arrSorted.length;i++){
if(arr[i] != arrSorted[i]){
count++;
// swap the index
let newIdx = indexMap.get(arrSorted[i]);
indexMap.set(arr[i],newIdx);
indexMap.set(arrSorted[i],i);
// sawp the values
[arr[i],arr[newIdx]] =[arr[newIdx],arr[i]];
}
}
return count;
}

Making a sum of arrays stop when the number 13 shows up but still return sum

I am VERY new to Javascript. I tried to look for an answer here but wasn't very lucky and maybe it's how I am asking. So, now I'm posting.
I have a loop in which I am to get a sum of the arrays. However, if the number 13 is in the array, then the loop stops adding numbers together but still return the numbers it added before it got to the 13. Right now, I have this as my code:
function sumNumbers(array) {
var sum = 0;
for(var i = 0; i < array.length; i++) {
sum += array[i];
if(array[i] == 13) {
break;
}
}
return sum;
}
I set the argument for the function which is 'array'. Then I thought I had to create a variable where the sum of the arrays will appear so I started it at 0 (I did try [] but tested it and it wasn't correct - still wanting to understand that). I understand that for any loop, you have to have the initialization which was i = 0, then the condition and then the final expression. So, since the number of elements is undefined, I used length. So, it says if the variable i is less than that number then it will keep going and keep adding to it. So I asked it to get a sum of all the arrays but if any number in a array is a 13, I need it to stop but still return the numbers it added before it reached 13.
Right now the function is defined, the sum of all arrays are returned and 0 is returned when its empty. But, I get this error
Expected 16 to deeply equal 3.
and can't figure out what I'm doing wrong. If anyone can help and explain it a little that would be awesome. This is my first question on here, so if I did it in an annoying way, thank you in advance!
If you need to stop adding when you find 13 and not include 13 in your sum then you need to check on the value of the next array element before you add it to your sum. I reversed two lines in your code. Please see the new version:
function sumNumbers (array) {
// First check if the array is a valid input to this function
if (typeof array == 'undefined')
return 0; // Or even better throw an exception
var sum = 0;
for (var i = 0; i < array.length; i++) {
if (array[i] == 13) { break; }
sum += array[i];
}
return sum;
}
Array.prototype.some
It's like forEach, but it stops looping whenever you return true. It was created for scenarios like yours.
let total = 0;
[3,7,4,3,2,1,13,44,66,8,408,2].some(num => {
if (num === 13) return true;
total += num;
});
console.log(total); //-> 20
Here's how you would use it:
function sumNumbers (arr) {
let total = 0;
arr.some(num => {
if (num === 13) return true;
total += num;
});
return total;
}
There are plenty ways of doing that... one of them:
function sumNumbers (array) {
var sum = 0;
for (var i = 0; array[i] != 13; i++) {
sum += array[i];
}
return sum;
}
About your:
Then I thought I had to create a variable where the sum of the arrays will appear so I started it at 0 (I did try [] but tested it and it wasn't correct - still wanting to understand that).
Well, if you make a variable initialize with [] you are setting an empty array. Remember that brackets [] are for arrays always.

Splice method not deleting items out of array

I'm trying to implement a function which takes three arguments(min, max, step)and generates a range of integers from min to max, with the step. The first integer is the minimum value, the second is the maximum of the range and the third is the step.
Here is an example of what it should look like:
generateRange(2, 10, 2) should return array of [2,4,6,8,10].
I'm using the splice method to remove any existing elements in the array that are greater than the max argument.
function generateRange(min, max, step) {
var arr = [];
var count = min;
for (var i = 0; i < max / step; i++) {
arr[i] = count;
count = count + step;
arr[i] > max ? arr.splice(i, 1) : arr[i];
}
return arr;
}
console.log(generateRange(2, 10, 2));
Whenever I console.log my result I get a bunch of commas after the last item...so it looks like this: [2,4,6,8,10, , , , ]
It doesn't appear to be deleting the items. What am I missing? Thanks!
The ternary operator is a bit strange, as the expression is not stored. It fixes the array by removing too large values. That works once, but if there is a second time, i will have increased, and by the assignment to arr[i], the array's length is again as if there had been no splice performed before (except for the undefined value at that i-1 index).
It would be better to exit the loop before assigning a value that is outside of the range. There is no sense in continuing the loop in such a case.
So make the count variable your loop variable and condition:
function generateRange(min, max, step){
var arr = [];
for(var count = min; count <= max; count+=step){
arr.push(count);
}
return arr;
}
var res = generateRange(2, 10, 2);
console.log(res);
A less readable, but shorter ES6 version would be:
function generateRange(min, max, step){
return Array.from(Array(Math.floor((max-min)/step)+1), (x,i) => min+i*step);
}
let res = generateRange(2, 10, 2);
console.log(res);

Javascript thinks 8 is larger than 12

function function1() {
arr = document.getElementById("textfield").value;
arr = arr.split(",");
length = arr.length;
largestNum = -9999;
for (i = 0; i < length; i++) {
if (arr[i] > largestNum) {
largestNum = arr[i];
}
}
alert("Largest number: " + largestNum);
}
can someone tell me what the hell is going on here, i have no idea why it's giving me 8 instead of 12
http://jsfiddle.net/qkLpA/15/
edit - fixed here: http://jsfiddle.net/qkLpA/12/
You're splitting a string, so each element of the resulting array will be a string. When you compare strings, it goes character-by-character, and 8 is larger than 1, so it never goes on to the 2.
The solution is to convert the items into numbers after splitting it:
arr = arr.split(",").map(function(s) { return parseInt(s, 10); });
If the map is confusing, you could also be less fancy and just use a for loop to convert them:
arr = arr.split(",");
for(var i = 0; i < arr.length; i++) {
arr[i] = parseInt(arr[i], 10);
}
You may also want to consider using -Infinity as the initial largestNum rather than -9999.
There's a much shorter way to get the largest humber:
function function1() {
var arr = document.getElementById("textfield").value;
arr = arr.split(",");
var max = Math.max.apply(null, arr);
alert("Largest number: " + max);
}
Fiddle
Your problem is that the .split() of the textfield string, creates an array of strings and not numbers. As a consequence, your comparison if (arr[i] > largestNum) in the for loop, is in reality a lexicographical comparison of strings, instead of a numerical comparison of integers, as you might have thought. That is why the "8" is larger than the "12".
You can confirm this in the updated jsfiddle which converts the strings to integers before comparing.

Categories