Calling a function inside another function in JavaScript - javascript

I have defined a function named larger to find the larger number between two arguments (num1, num2). Now I want to use this function inside another function called "largest" which gets an array and return the largest number of that array, but I`ve got stuck. Can anybody help me with that?
Here is my codes:
function larger(num1, num2){
var largerNumber = 0;
if (num1 > num2){
largerNumber = num1;
} else {
largerNumber = num2;
}
return largerNumber;
}
function largest(array){
for (var i = 0; i < array.length ; i++){
for (var j = 0; j < array.length ; j++){
if (array[i] != array[j]){
//I don`t know if I am doing it right
}
}
}
}

Just use Math.max:
function largest(array) {
return Math.max.apply(Math, array);
}
console.log(largest([5,-2,7,6]));
If you really want to use a custom binary larger function, consider [].reduce:
function larger(num1, num2) {
return num1 > num2 ? num1 : num2;
}
function largest(array) {
return array.reduce(larger, -Infinity);
}
console.log(largest([5,-2,7,6]));

The simpliest solution is tu use a max tmp value. This way, you only need to do one iteration over all your array.
function largest(array){
var max = array[0];
for (var i = 1; i < array.length ; i++) { // So we start at 1
max = larger(max, array[i]);
// Or use this : if(array[i] > max) max = array[i];
}
AS SAID BY ORIOL
I didn't check the length of the array, the above solution work only if the array.length > 0.
Otherwise, you'll have to check it usingsomething like this instead of var max = array[0];
function largest(array){
var max = -Infinity;
for (var i = 0; i < array.length ; i++) { Start at 0
max = larger(max, array[i]);
}
It really depends on the ergonomics of your IHM.

Iterate through the array once, keeping only the largest:
function larger(num1, num2){
var largerNumber = 0;
if (num1 > num2){
largerNumber = num1;
} else {
largerNumber = num2;
}
return largerNumber;
}
function largest(array){
let largestNumber = array[0];
for (var i = 1; i < array.length ; i++){
largestNumber = larger(largestNumber, array[i]);
}
return largestNumber;
}
var test = [1, 53, 352, 22, 351, 333, 123, 5, 25, 96];
console.log(largest(test));

If you are just trying to find the maximal value, you should go with Oriol's answer: Math.max
If you are looking for a way to call one function from another you can do it like this:
function first_function() {
//code of first function
//call to the other function
second_function();
}
function second_function() {
//code of second function
}

Set the first element of array to a variable, if next element in array is greater set variable to that element; continue process, return variable
function largest(array) {
if (!array.length) return;
for (var i = 0, curr = void 0; i < array.length ; i++) {
if (curr === void 0) curr = array[i];
else if (curr < array[i]) curr = array[i];
}
return curr
}
console.log(largest([2,20,2000,2,7]));

Related

What's the problem with this implementation of selection sort?

I am learning selection sort.
I am getting the correct output for some values, but not for all the values, don't know why??
Please find below code snippet:
function selectionSortRecursion(arr,p){
if( arr.length === 1){
return p;
}
min=arr[0];
for(var i =0;i<arr.length;i++){
if (arr[i]<min){
min = arr[i];
var minIdx=i;
}
}
temp=arr[0];
arr[0]=arr[minIdx];
arr[minIdx]=temp;
p.push(arr.shift());
return selectionSortRecursion(arr,p);
}
console.log(selectionSortRecursion([2,3,5,-3,20,0,2,6,-23],[]));
The problem is that the variable minIdx is not declared unless the body of the if statement inside the loop is executed. If the minimum element is at index 0, then arr[i] < min is never true and minIdx is undefined.
To solve it, write var minIdx = 0; before the loop, since min is initialised as the value at index 0. A couple of your other variables should be declared with var, too:
function selectionSortRecursion(arr, p) {
if(arr.length === 0) {
return p;
}
var min = arr[0];
var minIdx = 0;
for(var i = 1; i < arr.length; i++) {
if (arr[i] < min) {
min = arr[i];
minIdx = i;
}
}
var temp = arr[0];
arr[0] = arr[minIdx];
arr[minIdx] = temp;
p.push(arr.shift());
return selectionSortRecursion(arr, p);
}
Note that I've also changed the loop variable i to start at 1, since there's no need to compare index 0 with itself; and the base case of the recursion should be when arr.length is 0, not 1, to avoid losing the last element.

Why is this for loop not working?

What is the exactly difference between:
<p id="test"></p>
<script>
function findMax() {
var i;
var max = -Infinity;
for(i=0;i<arguments.length;i++) {
if(arguments[i] > max) {
max = arguments[i];
}
}
return max;
}
document.getElementById('test').innerHTML = findMax(32, 133, 83, 163);
</script>
and:
<p id="test"></p>
<script>
function findMax() {
var i = 0;
var max = -Infinity;
for(; i < arguments.length ; i++) {
if(arguments[i] > max) {
max = arguments[i];
}
}
return max;
}
document.getElementById('test').innerHTML = findMax(32, 133, 83, 163);
</script>
Maybe I have missed some classes but the first one outputs 163, as it should, while the second one outputs 0. The console says
SyntaxError: return not in function
return max;
Why does the second one return the lowest value, while the first one returns highest value?
while the second one outputs 0.
You didn't initialize i to 0.
Which means i was undefined, and undefined + 1 is NaN.
SyntaxError: return not in function
You missed a curly brace after for-loop, so the return statement went outside the function definition
function findMax() {
var i;
var max = -Infinity;
for(i = 0; i < arguments.length ; i++)
{//this was missed
if(arguments[i] > max)
{
max = arguments[i];
}
}
return max;
}
for the 2nd one you forget the opening bracket { and initial value i=0
You can also simply use Math.max()
in second you are missing a {, try:
function findMax() {
var i;
var max = -Infinity;
for(; i < arguments.length ; i++) {
if(arguments[i] > max) {
max = arguments[i];
}
}
return max;
}

Recursive Return Statement

This is a program that I have wrote to solve a problem. Check if there exists a sum of elements that equal to the maximum number in the array, return true if so, false otherwise.
var found = "false";
var max;
function ArrayAdditionI(array) {
max = Math.max.apply(null,array);
var p = array.indexOf(max);
array.splice(p,1);
array.sort(function(a, b){return a-b;});
found = findSum(array, 0, 0);
return found;
}
function findSum(array, sum, startIndex){
for(var i = startIndex; i < array.length ; i++){
sum += array[i];
if(sum === max){
found = "true";
break;
}else if(sum > max){
break;
}
if(i+2 < array.length && sum < max){
findSum(array, sum, i+2);
}
}
if(startIndex < array.length && sum !== max){
return findSum(array, 0, startIndex+1);
}
return found;
}
ArrayAdditionI(readline());
I had to use global variable, found, to indicate where a sum has been found or not. The return statement always returned undefined.
Also, if I use a return statement in the following if statement, the code does not work properly.
if(i+2 < array.length && sum < max){
return findSum(array, sum, i+2);
}
This is not the optimal solution to the problem, but this is the version I got working.
My question is Why am I getting undefined if I use return statement within the if statement. Also, I tried not using global and use return true if sum === max and at the very end return false, it always returns false or undefined.
-- UPDATE 2: Code with error results --
function ArrayAdditionI(array) {
var max = Math.max.apply(null,array);
//remove max element from array
var p = array.indexOf(max);
array.splice(p,1);
//sort array
array.sort(function(a, b){return a-b;});
//call find sum function
return findSum(array, 0, 0, max);
}
function findSum(array, sum, startIndex){
for(var i = startIndex; i < array.length ; i++){
sum += array[i];
if(sum === max){
return true;
}else if(sum > max){
break;
}
if(i+2 < array.length && sum < max){
**return** findSum(array, sum, i+2, max);
}
}
if(startIndex < array.length && sum !== max){
return findSum(array, 0, startIndex+1, max);
}
return false;
}
// calling the first function
ArrayAdditionI([ 7, 2,90, 31, 50 ]);
The start of the program is this call: ArrayAdditionI([ 7, 2,90, 31, 50 ]);
The return should be true.
Also, ArrayAdditionI([ 1,2,3,4 ]); is true.
However, ArrayAdditionI([ 1,2,3,100 ]); is false.
The return statement between ** **, when removed the code works, otherwise I either get false or undefined. I do not understand this part! Why does removing the return solves the problem, I thought every recursive call must be proceeded with a return statement.
Is the problem maybe due to multiple calls ? Am I using recursion in the improper way?
There are a few mistakes on your code that could lead to the error.
T.J. Crowder already said, use actual booleans instead of a string.
The found variable isn't defined inside your findSum function. That makes JavaScript assume you're setting a global variable.
Add var found = false; as the very first line of your findSum function.
Inside the last if inside your for there are a call to the findSum function but it's not returning it's value nor assigning it to the found variable.
Fix those and update your question with the results.
The following function should give you a true or false answer as to whether or not any combination of values inside an array produces the max figure.
var a = [
1, 1, 1, 1, 1, 1,
1, 1, 1, 9
]
var b = [1,1,1,5]
function MembersHoldMaxSum(arr) {
var i, r = false, index, max = Math.max.apply(null, arr), index;
for (i = 0; i <= arr.length - 1; i++) {
for (index = 0; index <= arr.length - 1; index++) {
var new_arr = [], ct;
for (ct = 0; ct <= arr.length - 1; ct++) {
if (index != ct) { new_arr.push(arr[ct]) }
}
while (new_arr.length != 1) {
var sum = 0, ct2 = 0;
for (ct2 = 0; ct2 <= new_arr.length - 1; ct2++) {
sum += new_arr[ct2];
}
if (sum == max) { return true }
new_arr.pop()
}
}
}
return r
}
var returns_true = MembersHoldMaxSum(a);
var returns_false = MembersHoldMaxSum(b);

Javascript Difference of any number

i want to write a JavaScript function which finds the difference between the biggest and the smallest number. Input may be any number, so I use arguments.
I wrote a max and a min function, alone they are working fine. I have put them in a difference function to calculate max-min and return the result.
But there is a bug somewhere, the code is not running as expected.
<!DOCTYPE html>
<html>
<body>
<p>Finding the difference.</p>
<p id="demo"></p>
<script>
function difference() {
var diff = 0;
function findMax() {
var i, max = 0;
for(i = 0; i < arguments.length; i++) {
if (arguments[i] > max) {
max = arguments[i];
}
}
return max;
}
function findMin() {
var i, min=Infinity;
for(i = 0; i < arguments.length; i++) {
if (arguments[i] < min) {
min = arguments[i];
}
}
return min;
}
diff=max-min;
return diff;
}
document.getElementById("demo").innerHTML = difference(4, 5, 6,88);
</script>
</body>
</html>
Try this instead
function difference() {
var i, val = parseFloat(arguments[0]), min = val, max = val;
for(i = 1; i < arguments.length; i++) {
val = arguments[i];
min = Math.min(val, min);
max = Math.max(val, max);
}
return max - min;
}
no need for infinity either
You never call either findMin() or findMax().
You can use the builtins Math.min() or Math.max() instead, they both take an unlimited number of arguments so you can avoid iterating over the arguments yourself.
Like so:
function difference() {
var min = Math.min.apply(null, arguments),
max = Math.max.apply(null, arguments);
return max - min;
}
If for some reason you wish to make use of your existing findMin() and findMax() methods, you are only missing the invocation of these methods.
Inside difference(), you should do this:
var numbers = Array.slice(arguments); // create an array of args
var max = findMax.apply(this, numbers);
var min = findMin.apply(this, numbers);
return max - min;
And do fix your findMax() method as suggested by a comment if you wish to handle negative numbers.
You can do it in one for loop much easier:
var numbers = [4, 8, 1, 100, 50];
function difference(arr) {
var max = arr[0]
var min = arr[0];
for(var i = 0; i < arr.length; i += 1) {
if(arr[i] > max) {
max = arr[i];
}
if(arr[i] < min) {
min = arr[i];
}
}
var d = max - min;
return d;
}
var result = difference(numbers);
console.log(result);

Variable amount of nested for loops

Edit: I'm sorry, but I forgot to mention that I'll need the values of the counter variables. So making one loop isn't a solution I'm afraid.
I'm not sure if this is possible at all, but I would like to do the following.
To a function, an array of numbers is passed. Each number is the upper limit of a for loop, for example, if the array is [2, 3, 5], the following code should be executed:
for(var a = 0; a < 2; a++) {
for(var b = 0; b < 3; b++) {
for(var c = 0; c < 5; c++) {
doSomething([a, b, c]);
}
}
}
So the amount of nested for loops is equal to the length of the array. Would there be any way to make this work? I was thinking of creating a piece of code which adds each for loop to a string, and then evaluates it through eval. I've read however that eval should not be one's first choice as it can have dangerous results too.
What technique might be appropriate here?
Recursion can solve this problem neatly:
function callManyTimes(maxIndices, func) {
doCallManyTimes(maxIndices, func, [], 0);
}
function doCallManyTimes(maxIndices, func, args, index) {
if (maxIndices.length == 0) {
func(args);
} else {
var rest = maxIndices.slice(1);
for (args[index] = 0; args[index] < maxIndices[0]; ++args[index]) {
doCallManyTimes(rest, func, args, index + 1);
}
}
}
Call it like this:
callManyTimes([2,3,5], doSomething);
Recursion is overkill here. You can use generators:
function* allPossibleCombinations(lengths) {
const n = lengths.length;
let indices = [];
for (let i = n; --i >= 0;) {
if (lengths[i] === 0) { return; }
if (lengths[i] !== (lengths[i] & 0x7fffffff)) { throw new Error(); }
indices[i] = 0;
}
while (true) {
yield indices;
// Increment indices.
++indices[n - 1];
for (let j = n; --j >= 0 && indices[j] === lengths[j];) {
if (j === 0) { return; }
indices[j] = 0;
++indices[j - 1];
}
}
}
for ([a, b, c] of allPossibleCombinations([3, 2, 2])) {
console.log(`${a}, ${b}, ${c}`);
}
The intuition here is that we keep a list of indices that are always less than the corresponding length.
The second loop handles carry. As when incrementing a decimal number 199, we go to (1, 9, 10), and then carry to get (1, 10, 0) and finally (2, 0, 0). If we don't have enough digits to carry into, we're done.
Set up an array of counters with the same length as the limit array. Use a single loop, and increment the last item in each iteration. When it reaches it's limit you restart it and increment the next item.
function loop(limits) {
var cnt = new Array(limits.length);
for (var i = 0; i < cnt.length; i++) cnt[i] = 0;
var pos;
do {
doSomething(cnt);
pos = cnt.length - 1;
cnt[pos]++;
while (pos >= 0 && cnt[pos] >= limits[pos]) {
cnt[pos] = 0;
pos--;
if (pos >= 0) cnt[pos]++;
}
} while (pos >= 0);
}
One solution that works without getting complicated programatically would be to take the integers and multiply them all. Since you're only nesting the ifs, and only the innermost one has functionality, this should work:
var product = 0;
for(var i = 0; i < array.length; i++){
product *= array[i];
}
for(var i = 0; i < product; i++){
doSomething();
}
Alternatively:
for(var i = 0; i < array.length; i++){
for(var j = 0; j < array[i]; j++){
doSomething();
}
}
Instead of thinking in terms of nested for loops, think about recursive function invocations. To do your iteration, you'd make the following decision (pseudo code):
if the list of counters is empty
then "doSomething()"
else
for (counter = 0 to first counter limit in the list)
recurse with the tail of the list
That might look something like this:
function forEachCounter(counters, fn) {
function impl(counters, curCount) {
if (counters.length === 0)
fn(curCount);
else {
var limit = counters[0];
curCount.push(0);
for (var i = 0; i < limit; ++i) {
curCount[curCount.length - 1] = i;
impl(counters.slice(1), curCount);
}
curCount.length--;
}
}
impl(counters, []);
}
You'd call the function with an argument that's your list of count limits, and an argument that's your function to execute for each effective count array (the "doSomething" part). The main function above does all the real work in an inner function. In that inner function, the first argument is the counter limit list, which will be "whittled down" as the function is called recursively. The second argument is used to hold the current set of counter values, so that "doSomething" can know that it's on an iteration corresponding to a particular list of actual counts.
Calling the function would look like this:
forEachCounter([4, 2, 5], function(c) { /* something */ });
This is my attempt at simplifying the non-recursive solution by Mike Samuel. I also add the ability to set a range (not just maximum) for every integer argument.
function everyPermutation(args, fn) {
var indices = args.map(a => a.min);
for (var j = args.length; j >= 0;) {
fn.apply(null, indices);
// go through indices from right to left setting them to 0
for (j = args.length; j--;) {
// until we find the last index not at max which we increment
if (indices[j] < args[j].max) {
++indices[j];
break;
}
indices[j] = args[j].min;
}
}
}
everyPermutation([
{min:4, max:6},
{min:2, max:3},
{min:0, max:1}
], function(a, b, c) {
console.log(a + ',' + b + ',' + c);
});
There's no difference between doing three loops of 2, 3, 5, and one loop of 30 (2*3*5).
function doLots (howMany, what) {
var amount = 0;
// Aggregate amount
for (var i=0; i<howMany.length;i++) {
amount *= howMany[i];
};
// Execute that many times.
while(i--) {
what();
};
}
Use:
doLots([2,3,5], doSomething);
You can use the greedy algorithm to enumerate all elements of the cartesian product 0:2 x 0:3 x 0:5. This algorithm is performed by my function greedy_backward below. I am not an expert in Javascript and maybe this function could be improved.
function greedy_backward(sizes, n) {
for (var G = [1], i = 0; i<sizes.length; i++) G[i+1] = G[i] * sizes[i];
if (n>=_.last(G)) throw new Error("n must be <" + _.last(G));
for (i = 0; i<sizes.length; i++) if (sizes[i]!=parseInt(sizes[i]) || sizes[i]<1){ throw new Error("sizes must be a vector of integers be >1"); };
for (var epsilon=[], i=0; i < sizes.length; i++) epsilon[i]=0;
while(n > 0){
var k = _.findIndex(G, function(x){ return n < x; }) - 1;
var e = (n/G[k])>>0;
epsilon[k] = e;
n = n-e*G[k];
}
return epsilon;
}
It enumerates the elements of the Cartesian product in the anti-lexicographic order (you will see the full enumeration in the doSomething example):
~ var sizes = [2, 3, 5];
~ greedy_backward(sizes,0);
0,0,0
~ greedy_backward(sizes,1);
1,0,0
~ greedy_backward(sizes,2);
0,1,0
~ greedy_backward(sizes,3);
1,1,0
~ greedy_backward(sizes,4);
0,2,0
~ greedy_backward(sizes,5);
1,2,0
This is a generalization of the binary representation (the case when sizes=[2,2,2,...]).
Example:
~ function doSomething(v){
for (var message = v[0], i = 1; i<v.length; i++) message = message + '-' + v[i].toString();
console.log(message);
}
~ doSomething(["a","b","c"])
a-b-c
~ for (var max = [1], i = 0; i<sizes.length; i++) max = max * sizes[i];
30
~ for(i=0; i<max; i++){
doSomething(greedy_backward(sizes,i));
}
0-0-0
1-0-0
0-1-0
1-1-0
0-2-0
1-2-0
0-0-1
1-0-1
0-1-1
1-1-1
0-2-1
1-2-1
0-0-2
1-0-2
0-1-2
1-1-2
0-2-2
1-2-2
0-0-3
1-0-3
0-1-3
1-1-3
0-2-3
1-2-3
0-0-4
1-0-4
0-1-4
1-1-4
0-2-4
1-2-4
If needed, the reverse operation is simple:
function greedy_forward(sizes, epsilon) {
if (sizes.length!=epsilon.length) throw new Error("sizes and epsilon must have the same length");
for (i = 0; i<sizes.length; i++) if (epsilon[i] <0 || epsilon[i] >= sizes[i]){ throw new Error("condition `0 <= epsilon[i] < sizes[i]` not fulfilled for all i"); };
for (var G = [1], i = 0; i<sizes.length-1; i++) G[i+1] = G[i] * sizes[i];
for (var n = 0, i = 0; i<sizes.length; i++) n += G[i] * epsilon[i];
return n;
}
Example :
~ epsilon = greedy_backward(sizes, 29)
1,2,4
~ greedy_forward(sizes, epsilon)
29
One could also use a generator for that:
function loop(...times) {
function* looper(times, prev = []) {
if(!times.length) {
yield prev;
return;
}
const [max, ...rest] = times;
for(let current = 0; current < max; current++) {
yield* looper(rest, [...prev, current]);
}
}
return looper(times);
}
That can then be used as:
for(const [j, k, l, m] of loop(1, 2, 3, 4)) {
//...
}

Categories