Related
I am going through the grokking algorithms book and trying to wrap my head around recursion. One of the challenges in the book is to "Write a recursive function to count the number of items in a list.". I came up with the following code, which works:
function recursiveArrayCount(arr, count) {
if (arr.length == 0) {
return 0;
} else {
arr.pop();
return count + recursiveArrayCount(arr, count);
}
}
let myArray = [1, 10, 23, 11, 4, 48, 88];
console.log(recursiveArrayCount(myArray, 1));
My question is, is there a better way to do this in javascript? In particular, I don't like having to seed the value of count with the initial '1' - but I can't think of another way to do it.
You don't need a second argument at all:
function recursiveArrayCount(arr) {
if (arr.length == 0) {
return 0;
}
return 1 + recursiveArrayCount(arr.slice(1));
}
Make a proper tail call by eliminating any reference to variables that would be needed after the recursive call returns.
function recursiveArrayCount(arr) {
return _recursiveCount(arr, 0);
function _recursiveCount(arr, count) {
return arr.length == 0 ? count : _recursiveCount(arr.slice(1), count + 1);
}
}
let myArray = [1, 10, 23, 11, 4, 48, 88];
console.log(recursiveArrayCount(myArray));
This makes it more likely to be optimized by reusing stack space.
Also, I used a nested function for the recursion, which ensures that the count is properly initialized.
You could also get a little fancy with the inner function, like this:
function recursiveArrayCount(arr) {
return (function _recursiveCount(arr, count) {
return arr.length == 0 ? count : _recursiveCount(arr.slice(1), count + 1);
})(arr, 0);
}
let myArray = [1, 10, 23, 11, 4, 48, 88];
console.log(recursiveArrayCount(myArray));
It's a recursively invoked IIFE.
sorry for the noob question probably, but I can't get my function to work. For me it looks very similar to the resolutions found on the web, but somehow it doesn't work and I can't tell where is the problem. Would be grateful for any help
function findvalue() {
var i = 0;
var array = [];
var min = array[0];
for (i = 0; i < array.length; i++) {
if (min > array[i]) {
min = array[i];
}
}
return min;
}
console.log(findvalue(11, 12, 13, 21, 22, 23, 97, 98, 99))
;
You could use arguments, an array like object of the function.
function findvalue() {
var i = 0,
min = arguments[0];
for (i = 1; i < arguments.length; i++) {
if (min > arguments[i]) {
min = arguments[i];
}
}
return min;
}
console.log(findvalue(11, 12, 13, 21, 22, 23, 97, 98, 99));
A shorter approach could be the use of rest parameters ... and spread syntax ... for the values for Math.min.
function findvalue(...args) {
return Math.min(...args)
}
console.log(findvalue(11, 12, 13, 21, 22, 23, 97, 98, 99));
Your function definition is incorrect, as well as how you are calling your function.
You are looking to iterate over an array, but you are calling your function with a bunch of numbers as the arguments. You instead need 1 parameter (argument) to call your function, which should be an array .
You have to instead call it this way:
findvalue([11, 12, 13, 21, 22, 23, 97, 98, 99])
Your function definition needs to be:
function findvalue(array) {
var i = 0;
var min = array[0];
for (i = 1; i < array.length; i++) {
if (min > array[i]) {
min = array[i];
}
}
return min;
}
As noted in the comments, you could modify your function definition to retain your initial way of calling the function. This is done by using rest parameters
The MDN docs describe rest parameters as:
The rest parameter syntax allows us to represent an indefinite number
of arguments as an array.
Call the function as you did: findvalue(11, 12, 13, 21, 22, 23, 97, 98, 99)
Your function definition would be:
function findvalue(...array) {
var i = 0;
var min = array[0];
for (i = 1; i < array.length; i++) {
if (min > array[i]) {
min = array[i];
}
}
return min;
}
You can use Math.min
function findMin() {
// arguments is an Array-like object corresponding to the arguments passed to a function.
return Math.min.apply(Math, arguments)
}
console.log(findMin(2,4,1,0,9,-2));
The missing thing in your function is the array must be a parameter of your function.
As you wrote it, the function is always trying to find the minimum in an empty array.
It is currently completely ignoring the example values you passed when you called your function.
So, instead of writing var array = [] in the body of you function, you have several possibilities :
1st possibility : take the array as parameter : declare your function as function(array) and change your call to actually pass an array of values : findValues([11, 12, 13, 21 ...]), and remove the var array = [] inside the body of your function.
2nd possiblity (my favorite): just replace var array = [] by var array = [...arguments]
Documention on the arguments object here : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments
(and also, please note that let is now best practice than var)
See Nina 's answer for full snippets examples with arguments
try like this
function findvalue() {
var order = Array.from(arguments).sort(function(a,b){ return a - b; });
var min = order[0];
//var max = order[order.length-1];
return min;
}
// MIN value
console.log(findvalue(23, 97, 98, 99, 11, 12, 13, 21, 22));
I am sure the Arrow function will simplify your work.
//Variable diclaration
var numbers = [11, 12, 13, 21, 22, 23, 97, 98, 99];
//Arrow Function to find Min Number
var minfinder = numbers.reduce((a, b) => Math.min(a, b));
//Consloe Output
console.log("Min Number is: " + minfinder);
I have a Javascript function called reverseArray that takes an array as the argument and returns a new array which has the same values as the input array in reverse order. I want to create a function called reverseArryInPlace which would change the value of the input array to the reverse order.
function reverseArray(inputArray) {
var outputArray = [];
for (var i = inputArray.length - 1; i >= 0; i--)
outputArray.push(inputArray[i]);
return outputArray;
}
function reverseArrayInPlace(inPlaceInputArray) {
inPlaceInputArray = reverseArray(inPlaceInputArray);
console.log('Inside reverseArrayInPlace: ' + inPlaceInputArray);
return inPlaceInputArray;
}
var arrayValue = [1, 2, 3, 4, 5];
reverseArrayInPlace(arrayValue);
console.log('Outside reverseArrayInPlace: ' + arrayValue);
// Expected Value: [5, 4, 3, 2, 1]
Here is the result I get when I execute this chunk of code:
Inside reverseArrayInPlace: 5,4,3,2,1
Outside reverseArrayInPlace: 1,2,3,4,5
Within the reverseArrayInPlace function the arrayValue variable has been reversed as expected. Why is it that when I reference the same variable outside the reverseArrayInPlace function, it is back to the original order?
If you want to reverse it in place, you have to reverse it in place.
function reverseArrayInPlace(array) {
for (let i = 0, j = array.length - 1; i < j; i++, j--)
[array[i], array[j]] = [array[j], array[i]];
}
const a = [1,2,3,4,5];
reverseArrayInPlace(a);
console.log(a);
The underlying problem here is that primitives are passed by value in JavaScript. See the following question for details:
Javascript by reference vs. by value
As a simple example, here is a function that attempts to mutate a string that was passed to it:
var outsideValue = 'foo'
function mutate(value) {
value = 'fish'
}
mutate(outsideValue);
console.log(outsideValue);
However, the console output is foo.
This happens because the value variable within the mutate function is a variable that has a reference to outsideValue when the function is initially invoked. When it is assigned the new value within the function body, it merely changes the value variable to reference a new string. As a result, the outsideValue is untouched.
Check this answer for an example that reverses in place:
https://stackoverflow.com/a/43486686/249933
Notice, that it does not re-assign the function argument.
As others have said, arrays are objects so they're passed by reference. You have to modify the original array, not create a new one.
So here's another version of reverseInPlace, it uses shift to remove the last element from the array and splice to insert it in the new location:
function reverseInPlace(arr) {
var i = arr.length;
while (i--) {
arr.splice(i, 0, arr.shift());
}
}
var arr = [1,2,3,4,5];
console.log('Before: ' + arr.join());
reverseInPlace(arr);
console.log('After: ' + arr.join());
For some fun, you can also leverage sort:
NB: this only works in some browsers, it's dependent on the built-in sort algorithm which is implementation dependent.
function reverseInPlace(arr) {
arr.sort(() => 1);
}
var arr = [47, 95, 80, 62, 8, 34, 31, 17, 62, 17, 85, 72, 51, 20, 68, 60, 30, 84, 7, 34];
console.log('Before: ' + arr.join());
reverseInPlace(arr);
console.log('After : ' + arr.join());
function reverseArray(inputArray) {
var outputArray = [];
for (var i = inputArray.length - 1; i >= 0; i--)
outputArray.push(inputArray[i]);
return outputArray;
}
function reverseArrayInPlace(inPlaceInputArray) {
inPlaceInputArray = reverseArray(inPlaceInputArray);
console.log('Inside reverseArrayInPlace: ' + inPlaceInputArray);
return inPlaceInputArray;
}
var arrayValue = [1, 2, 3, 4, 5];
**arrayValue = reverseArrayInPlace(arrayValue);**
alert('Outside reverseArrayInPlace: ' + arrayValue);
// Expected Value: [5, 4, 3, 2, 1]
//
your code is correct your just need to replace one line and write
arrayValue = reverseArrayInPlace(arrayValue);
instead of
reverseArrayInPlace(arrayValue);
Then arratValue will print expected values
I am trying to find a number by using the input to search in the array.
Got any idea why this does not work?
Every time i run the code i only get the message:
"Number does not exist"
var arr = [18, 21, 34, 42, 65, 63, 39, 13, 15, 24, -1, 14, 15];
var number = document.getElementById("find").value;
var svar = "";
function exists(){
for(i=0; i < arr.length; i++){
if(parseInt(arr[i]) == parseInt(number)){
svar++;
document.getElementById("existsArray").innerHTML = tall + "Number exists";
} else {
document.getElementById("existsArray").innerHTML = tall + "Number does not exist";
}
}
}
<p id="existsArray"></p>
<input placeholder="what number would you like to find?" id="find" type="number">
<button type="button" onclick="exists()">Finn tallet</button>
I replaced your for loop with indexOf
If you still want to use the loop you should break when you find the matching number
var arr = [18, 21, 34, 42, 65, 63, 39, 13, 15, 24, -1, 14, 15];
var svar = 0;
function exists() {
var number = +document.getElementById("find").value;
if (arr.indexOf(number) !== -1) {
svar++;
document.getElementById("existsArray").innerHTML = "Number exists";
} else {
document.getElementById("existsArray").innerHTML = "Number does not exist";
}
}
<input type="number" id="find" />
<button onclick="exists();">Does it exist ?</button>
<p id="existsArray"></p>
If you want to get the number of occurrence you should use this :
var occurrences = arr.filter(function (num) {return num === number;}).length
So your problem is that you don't exit the loop when you find the matching number. As a result, unless the number you are looking for is the very last number in your array, it will keep looping and the else clause will execute.
function exist() {
var number = parseInt(document.getElementById("find").value,10);
for(i=0; i < arr.length; i++){
if (exists === arr[i]) {
// number exists
break; // <-- this is important another alternative would be to just
// return at this point if the function doesn't do anything else
}
else {
// this number doesn't match, so we'll keep searching
}
}
}
Of course, this is much easier if you just use the built in functions Array.prototype.find or Array.prototype.indexOf
You can also use a filter to keep only values in the array wich match with input :
var arr = [18, 21, 34, 42, 65, 63, 39, 13, 15, 24, -1, 14, 15];
var input = "65";
var result = arr.filter(item => item === parseInt(input));
if (result.length === 0) console.log("number doesn't exist");
else console.log("number exists");
I've made some modifications to your code up front to help isolate your test case. If you look at this rework of your existing code, you'll see you get a message for each of your array elements, ending with "Number does not exist", which was your original problem. This is because that's the last message, overwriting your previous positive results.
var number = "42";
//var svar = "";
var svar = 0;//changing this from a string to a number. Can't ++ a string.
var myArray = [18, 21, 34, 42, 65, 63, 39, 13, 15, 24, -1, 14, 15];
/*
* #param {String} num - Passing the value that I'm looking for, rather than
* trying to pull it from elsewhere. This makes this much easier to test later.
* #param {Array} arr - Array of integers to search
*/
function exists(num, arr) {
for(i=0; i < arr.length; i++){
//if(parseInt(arr[i]) == parseInt(number)){
//No need to use parseInt here on the array. It's already a Number.
if(arr[i] == parseInt(number)){
svar++;/* I don't see any reason to be incrementing this. Perhaps it's elsewhere
in your implementation? */
//Using console.log() instead of elements not included in your code sample
console.log("Number exists");
} else {
//This keeps overwriting the above, except in a case where
//the last number would be a match!
console.error("Number does not exist");
}
}
}
exists(number, myArray);
If you want this to work as intended, you can either can eliminate your "Number does not exist" else branch, which will cause the positive message to remain, and you can leave your default text as "Number does not exist", or you simplify it, using what I'd recommend:
var number = "42",
number2 = "101",
myArray = [18, 21, 34, 42, 65, 63, 39, 13, 15, 24, -1, 14, 15];
var existsSimple = function (num, arr) {
return myArray.filter(function (itemNum) {return itemNum === parseInt(num);}).length > 0;
};
console.log('Number exists: ' + existsSimple(number, myArray));//true
console.log('Number exists: ' + existsSimple(number2, myArray));//false
nodeArray = [ 3, 3, 7, 6, 6, 7, 15, 10, 10, 14, 13, 13, 14, 15, 23, 18, 18, 22, 21, 21, 22, 23, 0 ];
nodes = [];
links = [];
function left(i) {
return 2*i + 1;
}
function right(i) {
return 2*i + 2;
}
function parent(i) {
console.log("Parent =" + (i-1)/2);
return (i-1)/2;
}
var index = 0;
do{
if (index === 0) {
var node = {
'value': nodeArray[index],
'child1_index': left(index),
'child1_value': nodeArray[left(index)],
'child2_index': right(index),
'child2_value': nodeArray[right(index)],
'parent_index' : 'null',
'parent_value' : 'null'
};
} else {
var node = {
'value': nodeArray[index],
'child1_index': left(index),
'child1_value': nodeArray[left(index)],
'child2_index': right(index),
'child2_value': nodeArray[right(index)],
'parent_index' :parent(index),
'parent_value' : nodeArray[parent(index)],
'index' : index
};
}
nodes.push(node);
index++;
} while (index != nodeArray.length)
console.log(nodes);
I have written the above code for future turning it into a binary tree with d3.js library, unfortunately all my parent node values (which are apparently given by any nodes (index -1 )/ 2. give numbers like 5.5 etc being half the index or something. which obviously wont work. Some nodes give full integers then some do not.
example console output for one of my node objects. which looks right
Node1:
parent_index:0
parent_value:3
example of other node objects. which dont look right are
Node2:
parent_index:0.5
parent_value:undefined
Here is a jsfiddle if anyone's interested
http://jsfiddle.net/mryfw095/5/
I think you just want your parent function to round down.
function parent(i) {
console.log("Parent =" + Math.floor((i-1)/2));
return Math.floor((i-1)/2);
}