Javascript for loop write to array undefined - javascript

Hi im doing the first part of eloquent javascript chp4 The Sum of a Range.
After spending some time i was sure i cracked the first part.
"Write a range function that takes two arguments, start and end,
and returns an array containing all the numbers from start
up to (and including) end."
I have looked at peoples answers but they all include the further parts of the question. I want to keep it simple, after all if i cant do the first part then there's no hope. it seems easy.
function range(start, end) {
let array = [];
for (let i = start; i <= end; i++){array.push(i);}
}
console.log(range(20 , 25));
but i get undefined, i have tried even copying and reducing the books answers to a similar situation.
It feels like my brain just cant do code. Where am i going wrong? Why is it undefined?
below is given answer
function range(start, end, step = start < end ? 1 : -1) {
let array = [];
if (step > 0) {
for (let i = start; i <= end; i += step) array.push(i);
} else {
for (let i = start; i >= end; i += step) array.push(i);
}
return array;
}
function sum(array) {
let total = 0;
for (let value of array) {
total += value;
}
return total;
}
console.log(range(1, 10))
// → [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
console.log(range(5, 2, -1));
// → [5, 4, 3, 2]
console.log(sum(range(1, 10)));
// → 55
thx guys

You are not returning anything from range. Use return array; in range function:
function range(start, end) {
let array = [];
for (let i = start; i <= end; i++){array.push(i);}
return array;
}
console.log(range(20 , 25));

The variable array is declared with let which gives it block scope. It is declared inside the function range
function range(start, end) {
let array = [];
for (let i = start; i <= end; i++){array.push(i);}
}
and its duration expires when the function terminates. It does not exist anymore afterwards.
As others have already said, return array.
This way a reference is kept for the line where it is called. And if assigned to another reference there, the duration of the array will be extended until unreferenced. Then it goes to garbage collection.
Example:
let arr = range(5,10);

the code for eloquent java script can be like this:
function range(start,end,step){
let myArr=[];
if(step){
for(let i=start;i<=end;i+=step){
myArr.push(i);
}
return myArr;
}
else{
for(let i=start;i<=end;i++){
myArr.push(i);
}
return myArr;}
}
function sum(arr){
let total=0;
for (let item of arr){
total +=item;
}
return total;
}
sum(range(1,10,2));

Related

Why i cant use for this way?

The plan is:
sort 'arr' from less to greater.
push values in range of both number from arr, inclusively.
find smallest common number which dividible on each value from 'arrForAll' without reminder.
Assign to 'i' first value from 'arrForAll'.
Output 'while' condition isn't false. Condition is: 'i' don't divide on each value from 'arrForAll' without reminder.
I tried this:
function smallestCommons(arr) {
let sortedArray = arr.sort();
let arrForAll = []
for (let i = sortedArray[0]; i < sortedArray[1] + 1; i++) {
arrForAll.push(i)
}
for (let i = sortedArray[1]; arrForAll.every(x => i % x !== 0); i += i) {
console.log(i)
}
return arr;
}
console.log(smallestCommons([1, 5]));
But console output nothing.
What's wrong in code?
In conditioin of for loop it must use logic operators '<','>', etc.
So this situation while loop is more suitable solution
function smallestCommons(arr) {
var i=0;
let sortedArray = arr.sort();//here store sorted value
let arrForAll=[]
for(let i=sortedArray[0];i<sortedArray[1]+1;i++){
arrForAll.push(i)
}//store [x to y]
while(true){
i+=sortedArray[1];
if(arrForAll.every(x => i % x == 0)){
break;
}
}
return i;}
console.log(smallestCommons([23, 18]));//returns 6056820, [1,5] will return 60

Create a function to slice without using slice()

I am trying to write a function called slice that accepts an array and two numbers.
The function should return a new array with the elements starting at the index of the first number and going until the index of the second number.
If a third parameter is not passed to the function, it should slice until the end of the array by default.
If the third parameter is greater than the length of the array, it should slice until the end of the array.
function slice(s, n, m) {
let a = [];
a = s.splice(n, m);
if(m === undefined || m > s.length) {
a = s.splice(n, s.length);
}
return a;
}
let s = [1, 2, 3, 4, 5];
slice(s, 1, 7);
output []
UPDATE:
Thanks for everyone's help; I GOT IT!!! happy dance
function slice(arr, start, end) {
let result = [];
from = Math.max(start, 0);
to = Math.min(end);
if((!end) || (end > arr.length)) {
for(let i = from; i<arr.length; i++) {
result.push(arr[i]);}
} else {
for(let i = from; i<to; i++) {
result.push(arr[i]);
}
}
return result;
}
slice([1, 2, 3, 4, 5], 2, 4);
The main problem is that .splice mutates the array, so on your first call to it you remove a part of the array (or in your case the whole array). Therefore if the code enters the if, and you call .splice a second time, the array is already empty. An if / else would work so that .splice gets only called once.
But that would still then not replicate the behaviour of .slice, as .slice does not mutate the original array. Therefore you rather need a loop, that copies one element after the other:
// if "do" doesn't get passed, initialize with array.length (default parameter)
function slice(array, from, to = array.length) {
// make sure the bounds are within the range
from = Math.max(from, 0);
to = Math.min(to, array.length);
// initialize an array we can copy values into
const result = [];
for(let index = from; index < to; index++) {
// left as an exercise :)
}
return result;
}
Answering this since the OP said the time for the homework has passed.
One way to solve this problem is to have two pointers to second and third arguments. If you have all the arguments given, this is how you should start
start = n
end = m
// if m is greater than length of s or if m is not given
if(m == undefined || m > s.length()){
end = s.length() - 1;
}
then it is a simple for loop from start to end, both inclusive.
int[] result = new int[end-start+1];
for(int i = start; i <= end; i++){
result[j] = s[i];
}
Code may not be syntactically correct but you can fix that.

How can I add a stopping instruction to my fibonacci sequence?

I am trying to use recursion to make the fibonacci algorithm. I would like to print all the fibonacci to this res variable and stop when I get past this num parameter. I would like to know how I can do this? This code:
function fibs(num) {
let i = 2;
let res = 0;
while (res < num) {
res = fibs(i - 1) + fibs(i - 2);
i++;
}
return res;
}
console.log(fibs(10));
I am getting a maximum call stack size exceeded error.
Notes:
⚠️ By using the first solution with small mistake like adding a big number, you can still exceed the maximum call stack size. If you think about the meaning of recursive function which is calling itself again and again, additionally it has a high calculation time.
👌 Using the second solution you are technically using only the current stack to calculate the result. Function looks larger but not that expensive.
Solutions:
First Solution - Recursive:
This solution just works much simpler than the original one if you still want to have a solution with recursion:
const fibs = (num) => {
if (num === 1 || num === 2) {
return 1;
}
return fibs(num - 1) + fibs(num - 2);
};
// 1, 1, 2, 3, 5, 8, 13, 21, 34, 55
for (let i = 1; i <= 10; i++) {
console.log(`fibs(${i}):`, fibs(i));
}
Second Solution - Non-Recursive:
There is always a better solution, if I would bet I would go rather for non recursive solution, please find an example below:
const fibs = (num) => {
if (num === 1 || num === 2) {
return 1;
}
let result = 1;
let resultPrevious = 1;
for(let i = 2; i < num; i++) {
const temp = result;
result += resultPrevious;
resultPrevious = temp;
}
return result;
};
// 1, 1, 2, 3, 5, 8, 13, 21, 34, 55
for (let i = 1; i <= 10; i++) {
console.log(`fibs(${i}):`, fibs(i));
}
I was interested how the non recursive solution is faster in case of running for fibs(30), please find the result below:
From the result, it seems the recursive solution was 98.86% slower at testing time for value 30.
I hope this helps!
Please try below code.
function fibs(num) {
let a = 0, b = 1;
console.log(a);
while (b < num) {
console.log(b);
const c = b;
b = a + b;
a = c;
}
}
fibs(100);
Other answers explained why your code has an issue.
Here is a simple way to write a recursive function that captures the Fibonacci numbers up to num:
const fibsTo = (num, a = 0, b = 1) =>
a > num
? []
: [a, ... fibsTo (num, b, a + b)]
console .log (fibsTo (10))
This stores the current state (the most recent two values, a and b) in parameters passed through the recursive calls, starting with default values. This returns [0, 1, 1, 2, 3, 5, 8]. If you prefer to start with [1, 1, 2, 3, ...], then change the function to start with a = 1, b = 1.
This is not tail-recursive, and could eventually run out of stack space. When tail-call optimization finally becomes ubiquitous in JS, there will be reasons to use tail-recursive versions, and it doesn't hurt to do so now. A tail-recursive version might look like this:
const fibsTo = (num, fibs = [], a = 0, b = 1) =>
a > num
? fibs
: fibsTo (num , [...fibs, a], b, a + b)
But there is another reason that such tail-recursion isn't so important for this problem: Long before you run out of stack space, you will run past the precision of Javascript integers. In fact, while Fibonacci # 79 is actually 14472334024676221, JS techniques like this will produce 14472334024676220, and the error will compound from there. This can be fixed by using BigInts, but it won't matter until there is wider support for proper tail calls.
This function has approximately the same running speed as the non-recursive version from norbitrial's answer, so as expected, recursion is not a performance-killer on a fundamentally recursive problem.
using recursion is not the appropriate way when expecting a lot of calls.
this will make your code working slower, and in some cases - reach the maximum call stack size and get no answer.
the right way to do it is using array, like this:
function fibs(num) {
let i = 1;
let arr = [1, 1];
while (arr[i] < num) {
arr.push(arr[i-1] + arr[i]);
i++;
}
return arr[i];
}
Here's a snippet of what should you write to accomplish your task
function fibs(num) {
let res = 0;
let a = 0, b = 1;
while(res < num){
res = a + b;
a = b;
b = res;
}
return res;
}
console.log(fibs(10));
Because its not a recursion, its an infinite loop you are dealing with.
your code increment i (i++) but it dosent check in the while loop.
you can try this out:
function fibs(num) {
if (num>1) {
return (fibs(num - 1) + fibs(num - 2));
}
return num;
}

javascript weird console logs

I've got a assignment to make function that gives you a sorted array with 6 random numbers from 1 to 45. None of the array values should equal to one another.
I thought about a solution that would work in Java but the JavaScript console logs I get are pretty confusing. Could anyone help me out?
"use strict";
var numbers = [];
for(var x = 1; x <46;x++){
numbers.push(x);
}
function LottoTipp(){
var result = [];
for(var i = 0; i <6; i++){
var randomNum = Math.round(Math.random()* 45);
var pushed = numbers[randomNum];
result.push(pushed);
numbers.splice(randomNum)
}
return console.log(result) + console.log(numbers);
}
LottoTipp();
the console logs
[ 34, 7, undefined, undefined, undefined, undefined ]
[ 1, 2, 3, 4, 5, 6 ]
There were three problems:
If you want to remove one item of an array you have to splice it by the items index and give a deletecount.
In your case: numbers.splice(randomNum, 1);
You have to use Math.floor instead of Math.round, because Math.floor always down to the nearest integerer, while Math.round searches for the nearest integer wich could be higher than numbers.length.
After removing one item the length of the array has been changed. So you have to multiply by numbers.lenght instead of 45.
In your case: var randomNum = Math.floor(Math.random()* numbers.length);
"use strict";
var numbers = [];
for(var x = 1; x < 46; x++){
numbers.push(x);
}
function LottoTipp(){
var result = [];
for(var i = 0; i < 6; i++){
var randomNum = Math.floor(Math.random()* numbers.length);
var pushed = numbers[randomNum];
result.push(pushed);
numbers.splice(randomNum, 1);
}
return console.log(result) + console.log(numbers);
}
LottoTipp();
If you only want an array with random unique numbers I would suggest doing it like this:
<script>
var array = [];
for(i = 0; i < 6; i++) {
var number = Math.round(Math.random() *45);
if(array.indexOf(number) == -1) { //if number is not already inside the array
array.push(number);
} else { //if number is inside the array, put back the counter by one
i--;
}
}
console.log(array);
</script>
There is no issue with the console statement the issue is that you are modifying the numbers array in your for loop. As you are picking the random number between 1-45 in this statement:-
var randomNum = Math.round(Math.random()* 45);
and you expect that value would be present in the numbers array at that random index. However you are using array.splice() and providing only first parameter to the function. The first parameter is the start index from which you want to start deleting elements, find syntax here. This results in deleting all the next values in the array.Therefore if you pick a random number number say.. 40, value at numbers[40] is undefined as you have deleted contents of the array.
if you want to generate unique set of numbers follow this post.
hope it helps!
Just add the number in the result if it is unique otherwise take out a new number and then sort it. Here is an implementation:
let result = []
while(result.length < 6) {
let num = Math.round(Math.random() * 45);
if(!result.includes(num)) {
result.push(num);
}
}
result.sort((a,b) => {
return parseInt(a) - parseInt(b);
});
console.log(result);

Shuffle an array as many as possible

I have an array like this
[0,2,3]
The possible shuffling of this array are
[0,2,3], [2,3,0], [3,0,2], [3,2,0], [0,3,2], [2,0,3]
How can I get these combinations? The only idea I have in mind currently is
n = maximum num of possible combinations, coms = []
while( coms.length <= n )
temp = shuffle( original the array );
if temp is there in coms
return
else
coms.push(temp);
But I do not think this is efficient, as here we are blindly depending on uniform distribution of shuffle method.
Is there alternative findings for this problem?
The first thing to note is that the number of permutations increases very fast with regard to the number of elements (13 elements = 6 bilion permutations), so any kind of algorithm that generates them will deteriorate in performance for a large enough input array.
The second thing to note is that since the number of permutations is very large, storing them in memory is expensive, so you're way better off using a generator for your permutations and doing stuff with them as they are generated.
The third thing to note is that recursive algorithms bring a large overhead, so even if you find a recursive solution, you should strive to get a non-recursive one. Obtaining a non-recursive solution if a recursive one exists is always possible, but it may increase the complexity of the code.
I have written a non recursive implementation for you, based on the Steinhaus–Johnson–Trotter algorithm (http://en.wikipedia.org/wiki/Steinhaus%E2%80%93Johnson%E2%80%93Trotter_algorithm)
function swap(arr, a,b){
var temp = arr[a];
arr[a]=arr[b];
arr[b]=temp;
}
function factorial(n) {
var val = 1;
for (var i=1; i<n; i++) {
val *= i;
}
return val;
}
function permute(perm, func){
var total = factorial(perm.length);
for (var j=0, i=0, inc=1; j<total; j++, inc*=-1, i+=inc) {
for (; i<perm.length-1 && i>=0; i+=inc) {
func.call(perm);
swap (perm, i, i+1);
}
func.call(perm);
if (inc === 1) {
swap(perm, 0,1);
} else {
swap(perm, perm.length-1, perm.length-2);
}
}
}
console.clear();
count = 0;
permute([1,2,3,4,5,6], function(){console.log(this); count++;});
console.log('There have been ' + count + ' permutations');
http://jsbin.com/eXefawe/2/edit
Try a recursive approach. Here's a hint: every permutation of [0,2,3] is either
[0] plus a permutation of [2,3] or
[2] plus a permutation of [0,3] or
[3] plus a permutation of [0,2]
As zodiac mentioned the best solution to this problem is a recursive one:
var permute = (function () {
return permute;
function permute(list) {
return list.length ?
list.reduce(permutate, []) :
[[]];
}
function permutate(permutations, item, index, list) {
return permutations.concat(permute(
list.slice(0, index).concat(
list.slice(index + 1)))
.map(concat, [item]));
}
function concat(list) {
return this.concat(list);
}
}());
alert(JSON.stringify(permute([1,2,3])));
Hope that helps.
All permutations of a set can be found by selecting an element in the set and recursively permuting (rearranging) the remaining elements. Backtracking approach can be used for finding the solution.
Algorithm steps (source):
Pseudocode (source):
permute(i)
if i == N output A[N]
else
for j = i to N do
swap(A[i], A[j])
permute(i+1)
swap(A[i], A[j])
Javascript implementation (jsFiddle):
Array.prototype.clone = function () {
return this.slice(0);
};
var input = [1, 2, 3, 4];
var output = [];
function permute(i) {
if (i == input.length)
output.push(input.clone());
else {
for (var j = i; j < input.length; j++) {
swap(i, j);
permute(i + 1);
swap(i, j); // backtrack
}
}
};
function swap(i, j) {
var temp = input[i];
input[i] = input[j];
input[j] = temp;
}
permute(0);
console.log(output);
For an array of length n, we can precompute the number of possible permutations. It's n! (n factorial)
function factorial(n){ return n<=0?1:n*factorial(n-1);}
//There are better ways, but just for illustration's sake
And, we can create a function which maps an integer p between 0...n!-1 to a distinct permutation.
function map(p,orgArr){
var tempArr=orgArr.slice(); //Create a copy
var l=orgArr.length;
var permArr=[];
var pick;
do{
pick=p%l; //mod operator
permArr.push(tempArr.splice(pick,1)[0]); //Remove item number pick from the old array and onto the new
p=(p-pick)/l;
l--;
}while(l>=1)
return permArr;
}
At this point, all you need to do is create an array ordering=[0,1,2,3,...,factorial(n)-1] and shuffle that. Then, you can loop for(var i=0;i<=ordering.length;i++) doSomething(map(ordering[i],YourArray));
That just leaves the question of how to shuffle the ordering array. I believe that's well documented and outside the scope of your question since the answer depends on your application (i.e. is pseudo random good enough, or do you need some cryptographic strength, speed desired, etc...). See How to randomize (shuffle) a JavaScript array? and many others.
Or, if the number of permutations is so large that you don't want to create this huge ordering array, you just have to distinctly pick values of i for the above loop between 0-n!-1. If just uniformity is needed, rather than randomness, one easy way would be to use primitive roots: http://en.wikipedia.org/wiki/Primitive_root_modulo_n
you don't need to recurse. The demo should make the pattern pretty clear: http://jsfiddle.net/BGYk4/
function shuffle(arr) {
var output = [];
var n = arr.length;
var ways = [];
for(var i = 0, j = 1; i < n; ways.push(j *= ++i));
var totalWays = ways.pop();
for(var i = 0; i < totalWays; i++) {
var copy = arr.slice();
output[i] = [];
for(var k = ways.length - 1; k >= 0; k--) {
var c = Math.floor(i/ways[k]) % (k + 2);
output[i].push(copy.splice(c,1)[0]);
}
output[i].push(copy[0]);
}
return output;
}
this should output all possible "shuffles"
console.log(shuffle(['a', 'b', 'c', 'd', 'e']));
this one's cuter (but the output from the other example is much clearer): http://jsfiddle.net/wCnLf/
function shuffle(list) {
var shufflings = [];
while(true) {
var clone = list.slice();
var shuffling = [];
var period = 1;
while(clone.length) {
var index = Math.floor(shufflings.length / period) % clone.length;
period *= clone.length;
shuffling.push(clone.splice(index,1)[0]);
}
shufflings.push(shuffling);
if(shufflings.length == period) return shufflings;
}
}
and of course it still outputs all possible "shuffles"
console.log(shuffle(['a', 'b', 'c', 'd', 'e']));
tibos example above was exactly what I was looking for but I had some trouble running it, I made another solution as an npm module:
var generator = new Permutation([1, 2, 3]);
while (generator.hasNext()) {
snippet.log(generator.next());
}
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
<script src="http://rawgit.com/bcard/iterative-permutation/master/iterative-permutation.js"></script>
https://www.npmjs.com/package/iterative-permutation
https://github.com/bcard/iterative-permutation

Categories

Resources