Recursion method - javascript

Something's not working with this method. Where's the error?
find the Odd numbers:
array = [1,2,3,4,5,6,7,8,9,10]
function findOddNum(array) {
let result = [];
let i = 0;
function helper_func(inputArray) {
if (inputArray.length === 0) {
return false;
}
if (inputArray[i] % 2 !== 0) {
result = inputArray[i];
}
i++;
helper_func(array);
}
helper_func(array);
return result;
}
const res = findOddNum([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
console.log(res);
It returns the following error:
maximum call stack size not exceeded

You haven't added the nested function termination condition
if (i >= inputArray.length) return;
Without termination condition, it will go infinite recursion. That's the reason it gives you maximum call stack size not exceeded
function findOddNum(array) {
let result = [];
let i = 0;
function helper_func(inputArray) {
if (i >= inputArray.length) return; // change
if (inputArray.length === 0) {
return false;
}
if (inputArray[i] % 2 !== 0) {
result.push(inputArray[i]);
}
i++;
helper_func(array);
}
helper_func(array);
return result;
}
const res = findOddNum([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
console.log(res);
BTW You don't have to use recursion just to get the odd numbers, It is one liner solution
array.filter((num) => num % 2)
function findOddNum(array) {
return array.filter((num) => num % 2);
}
const res = findOddNum([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
console.log(res);

in case of recursion you need to give a base condition (termination condition), else it would go in an infinite loop
add the below line in helper_func
if(i>=inputArray.length)
return false;
function findOddNum(array) {
let result = [];
let i = 0;
function helper_func(inputArray) {
if (inputArray.length === 0) {
return false;
}
if(i>=inputArray.length){
return false;
}
if (inputArray[i] % 2 !== 0) {
result = inputArray[i];
}
i++;
helper_func(array);
}
helper_func(array);
return result;
}
const res = findOddNum([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
console.log(res);

Related

How to return all items in array that don't have their opposite?

I have for example this array [-3, 1, 2, 3, -1, 4, -2], and I'd like to return 4 because it doesn't have its own opposite. I've been struggling for several hours to understand how to implement the algorithm.
This is what I've done so far:
let numbers = [-3, 1, 2, 3, -1, 4, -2];
let sortedNumebrs = [];
//It returns the numbers array sorted
function sortedArray() {
sortedNumebrs = numbers.sort((a, b) => a - b);
return sortedNumebrs;
}
// It return an array with all positive numbers
function positive() {
let positive = sortedArray().filter((e) => Math.sign(e) === 1);
return positive;
}
// It return an array with all negative numbers
function negative() {
let negative = sortedNumebrs.filter((e) => Math.sign(e) === -1);
negative = negative.sort((a, b) => a + b);
return negative;
}
// It returns the array longer
function minLength() {
let minNum = Math.min(positive().length, negative().length);
if (minNum === positive().length) {
return positive()
} else {
eturn negative();
}
}
// It returns the array shorter
function maxLength() {
let maxNum = Math.max(positive().length, negative().length);
if (maxNum === positive().length) {
return positive()
} else {
return negative();
}
}
// Function that should return string if each numbers has its
// own opposite otherwise 4
function opposite() {
let result = (minLength() === maxLength()) ? true : false;
if (result) {
return 'Each element has own opposite';
} else {
// some code
}
}
You can try something like this:
const yourArray =[-3, 1, 2, 3, -1, 4, -2];
const result = [];
for (let el1 of yourArray) {
let hasOpposite = false;
for (let el2 of yourArray) {
if (el1 === -el2) {
hasOpposite = true;
break;
}
}
if (!hasOpposite) {
result.push(el1);
}
}
console.log(result); // [4]
or using array functions:
const yourArray = [-3, 1, 2, 3, -1, 4, -2];
const itemsWithoutOpposite = yourArray.filter(el1 => !yourArray.includes(-el1));
Here's another approach. This one assumes that duplicates need matching too, so if I have [1, -1, 1] that final 1 should have an additional -1 to match, rather than using the -1 that was matched by the initial 1. It will also not match an element with itself, so if you have a 0 you will need another zero to match.
const yourArr = [-3, 1, 2, 3, -1, 4, -2];
const result = [...yourArr];
for (let i = 0; i < result.length; i++) {
let el = result[i];
let inverse = result.indexOf(-el, i + 1);
if (inverse !== -1) {
result.splice(inverse, 1);
result.splice(i, 1);
i--;
}
}
console.log(result);

Solution to Euler Problem 5: My code doesn't work

I have a problem with Project Euler challenge 5. The challenge is based on finding the smallest positive number that is divisible by all the numbers from 1 to 20. This is my code:
let i = 1;
function myFunction (num) {
return i % num == 0
}
while (true) {
let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
if (arr.every(myFunction)) {
console.log(i)
break;
} else {
i++
continue;
}
}
The code up to number 16 works fine (720720), but once I add another number to the array, in order (16, 17, 18, ...) it doesn't work anymore. I don't know why, I'm very new to programming. If you could instruct me.
The answer above takes way to long, like he said, quite a few seconds.
This code is longer but takes less than a second to come up with the result.
const divisibleByAllToN = (n) => {
const twoToN = Array(n - 1)
.fill(2)
.map((item, index) => item + index);
let numbersToBeMultiplied = twoToN.filter((item) => {
for (var i = 2; i < item; i++) if (item % i === 0) return false;
return item > 1;
});
numbersToBeMultiplied = numbersToBeMultiplied.map((item) => {
let value = item;
while (value * item <= n) {
value = value * item;
}
return value;
});
return numbersToBeMultiplied.reduce((acc, val) => acc * val);
};
divisibleByAllToN(20);
solved :
you need to return a condition in myFunction in order for array.every to work properly :
let i = 1;
function myFunction (num) {
var result = i / num
return parseInt(result) === result // condition HERE to check if result is an int
}
while (true) {
let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
if (arr.every(myFunction)) {
console.log(i)
break;
} else {
i++
continue;
}
}
doing this we get (after about 20 seconds) the right result : 232792560

Reverse numbers in function without using ".reverse" method in Javascript

function revertNumbers(...numberArray) {
let rev = [];
for(let i = 0; i <numberArray.length; i++)
{
rev.push(numberArray[i])
}
return rev.reverse();
}
console.log("revertNumbers", revertNumbers(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) === "9,8,7,6,5,4,3,2,1,0");
Can you please show me the how to reverse number in this code that the statement will be true? Also without using .reverse method. Is it possible to make it in another for loop by just changing this statement:
(let i = 0; i <numberArray.length; i++)
You just need to reverse the direction of your loop. Means start i with last index and then gradually decrease it to 0
function revertNumbers(...numberArray) {
let rev = [];
for(let i = numberArray.length - 1; i >= 0; i--)
{
rev.push(numberArray[i])
}
return rev.join(",")
}
console.log("revertNumbers", revertNumbers(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) === "9,8,7,6,5,4,3,2,1,0");
This is also a good use case of reduceRight()
const revertNumbers = (...arr) => arr.reduceRight((ac, a) => ([...ac, a]), []).join(',')
console.log("revertNumbers", revertNumbers(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) === "9,8,7,6,5,4,3,2,1,0");
Here is a solution that manipulates the array in place, and only has to traverse half of the original array in order to reverse it. This ekes out some modest performance gains compared to other answers in this thread (my function narrowly beats out or matches the speed of even the native reverse method in ops/sec), but micro-optimizations are largely irrelevant for this problem unless you are talking about a truly massive list of numbers.
Nonetheless, here is my answer:
const revNums = (...numArray) => {
for (
let arrLen = numArray.length,
breakPoint = ((arrLen / 2)|0) - 1,
i = arrLen,
k = 0,
temp;
--i !== breakPoint;
++k
) {
temp = numArray[i];
numArray[i] = numArray[k];
numArray[k] = temp;
}
return numArray.join(',');
};
You could reduce the original array and unshift each element onto the new array.
function revertNumbers(...numberArray) {
return numberArray.reduce((r, e) => { r.unshift(e); return r }, []).join(',')
}
console.log("revertNumbers", revertNumbers(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) === "9,8,7,6,5,4,3,2,1,0")
If you don't want to unshift, you can concat in reverse.
function revertNumbers(...numberArray) {
return numberArray.reduce((r, e, i, a) => r.concat(a[a.length - i - 1]), []).join(',')
}
console.log("revertNumbers", revertNumbers(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) === "9,8,7,6,5,4,3,2,1,0")
You could take a value and the rest of the arguments and use a recursive approach to get a reversed array of arguments.
function revertNumbers(v, ...rest) {
return rest.length
? [...revertNumbers(...rest), v]
: [v];
}
console.log(revertNumbers(0, 1, 2, 3, 4, 5, 6, 7, 8, 9));
It is to ask how many solutions can be possible ?
here are 3 of them...
"use strict";
const targetString = '9,8,7,6,5,4,3,2,1,0'
;
function soluce_1(...numberArray)
{
const rev = [];
for( let i=numberArray.length;i--;) { rev.push(numberArray[i]) }
return rev.join(',')
}
function soluce_2(...numberArray)
{
const rev = [];
let pos = numberArray.length;
for(let N in numberArray) { rev[--pos] = N }
return rev.join(",")
}
function soluce_3(...numberArray)
{
const rev = [];
while(numberArray.length) { rev.push(numberArray.pop()) }
return rev.join(',')
}
console.log('soluce_1 ->', (soluce_1(0,1,2,3,4,5,6,7,8,9)===targetString) );
console.log('soluce_2 ->', (soluce_2(0,1,2,3,4,5,6,7,8,9)===targetString) );
console.log('soluce_3 ->', (soluce_3(0,1,2,3,4,5,6,7,8,9)===targetString) );
And yes, I code in Whitesmiths style, please respect this (the reason for the downVote for correct answers ?)
https://en.wikipedia.org/wiki/Indentation_style#Whitesmiths_style
You might reverse like this:
function reverse(...a) {
const h = a.length >> 1, l = a.length-1;
for (let i = 0; i < h; ++i) [a[i], a[l-i]] = [a[l-i], a[i]];
return a;
}
console.log(reverse(0, 1, 2, 3, 4, 5, 6, 7, 8, 9).join(','));

Recursion is skipping values

I'm trying to assign/place a set of numbers randomly within a new array as a pair: [1,2,3,4,5,6,7,8] should equal [[1,1],[8,8],[3,3],[7,7],[2,2],[4,4],[5,5],[6,6]]
let numbers = [1,2,3,4,5,6,7,8]
let arrayToBeFilled = [];
function assign(num) {
let randomNumber = Number(Math.floor((Math.random() * 8)));
if(arrayToBeFilled[randomNumber] == null ) {
arrayToBeFilled[randomNumber] = [num, num] ;
} else if (arrayToBeFilled[randomNumber] == Array) {
return assign(num);
} else {
console.log('Trying a new number');
}
}
for (num in numbers) {
assign(Number(num));
}
console.log(arrayToBeFilled);
return arrayToBeFilled;
Returns the array but with values missing where the recursion should have filled the array (what I'm expecting at least). See <1 empty item>.
Trying a new number
Trying a new number
Trying a new number
[ [ 0, 0 ], [ 7, 7 ], [ 5, 5 ], <1 empty item>, [ 2, 2 ], [ 1, 1 ] ]
Anyone have any idea why this is happening??
I made some edits to your code:
/* prefer functions instead of global variables */
function main() {
let numbers = [1, 2, 3, 4, 5, 6, 7, 8]
let arrayToBeFilled = [];
for (num of numbers) { /* Use 'for...of' syntax for array iteration */
assign(Number(num), arrayToBeFilled);
}
return arrayToBeFilled
}
function assign(num, arr) {
const randomNumber = Number(Math.floor((Math.random() * 8)));
if (arr[randomNumber] == null) {
arr[randomNumber] = [num, num];
} else if (Array.isArray(arr[randomNumber])) { /* Proper way to check if element is an Array type */
return assign(num, arr);
} else {
return []
}
}
console.log(main());
Here's my take. The beauty of this is of course the abstraction in form of the shuffle function which works on all arrays, and can be put away into a utility sub file.
function shuffle(a) {
// you can replace this with "let n = a" if you don't care about
// the incoming array being altered
let n = [...a];
for (let i = n.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[n[i], n[j]] = [n[j], n[i]];
}
return n;
}
let numbers = [1,2,3,4,5,6,7,8];
console.log( shuffle( numbers ).map( n => [n,n] ) );
You could create function that will randomize elements and return array of the nth length for each element using while loop.
let numbers = [1, 2, 3, 4, 5, 6, 7, 8]
function randomize(data, n) {
const result = [];
data = data.slice();
while (data.length) {
const pos = Math.floor(Math.random() * data.length);
const el = data.splice(pos, 1).pop();
result.push(Array.from(Array(n), () => el));
}
return result;
}
console.log(randomize(numbers, 2))
console.log(randomize(numbers, 4))
Try the following:
function assign(num) {
let randomNumber = Number(Math.floor((Math.random() * 8)));
if(arrayToBeFilled[randomNumber] == null ) {
arrayToBeFilled[randomNumber] = [num + 1, num + 1] ;
} else {
assign(num);
}
}
You had an else in the code which was skipping one place in the array to be filled
NON-REPEATING random numbers (https://jsfiddle.net/th3vecmg/2/)
let numbers = [1, 2, 3, 4, 5, 6, 7, 8]
let arrayToBeFilled = [];
function assign(numbers, i, size) {
if (i < size) {
assign(numbers, ++i, size);
}
var randomNumber = numbers[Math.floor(Math.random() * numbers.length)];
arrayToBeFilled.push([randomNumber, randomNumber]);
numbers.splice(numbers.indexOf(randomNumber), 1);
}
assign(numbers, 0, numbers.length - 1)
console.log(arrayToBeFilled);
REPEATING random numbers (https://jsfiddle.net/th3vecmg/3/)
let numbers = [1, 2, 3, 4, 5, 6, 7, 8]
let arrayToBeFilled = [];
function assign(numbers, i) {
let randomNumber = Number(Math.floor((Math.random() * 8)));
arrayToBeFilled[i] = [randomNumber, randomNumber];
if (i < numbers.length - 1) {
assign(numbers, ++i);
}
}
assign(numbers, 0)
console.log(arrayToBeFilled);

I need to write a function that loops through an array of numbers, and returns the odd & even numbers in it's array.

I need to write a function that loops through an array of numbers, and returns the odd & even numbers in it's array.
I'm not sure if there's a better way to do this, and I'm stuck. Is there a way to return both statements?
var myNums = [1, 2, 3, 4, 5, 6, 7, 9];
var evens = [];
var odds = [];
function oddsAndEvens(nums) {
for(var i = 0; i < nums.length; i++){
if(nums[i] % 2 === 0){
evens.push(nums[i])
}
else if (!nums[i] % 2 === 0) {
odds.push(nums[i])
}
}
console.log(evens);
console.log(odds);
//I need it to "return" the array,
//not console log
}
console.log(oddsAndEvens(myNums));
A clean function to separate the evens from the odds.
function arrangeNums(array) {
let odd = array.filter(i=>i%2!==0);
let even = array.filter(i=>i%2===0);
return {even:even,odd:odd};
}
console.log(arrangeNums([...Array(100).keys()]));
return arrays instead of console.log should work
var myNums = [1, 2, 3, 4, 5, 6, 7, 9];
var evens = [];
var odds = [];
function oddsAndEvens(nums) {
for(var i = 0; i < nums.length; i++){
if(nums[i] % 2 === 0){
evens.push(nums[i])
}
else if (!nums[i] % 2 === 0) {
odds.push(nums[i])
}
}
// return array of values you want
return [evens, odds]
}
console.log(oddsAndEvens(myNums));
You could use an object for the result and taken an array for the keys of the object to push the value.
function getGrouped(array) {
return array.reduce(function (r, a) {
r[['even', 'odd'][a % 2]].push(a);
return r;
}, { odd: [], even: [] });
}
var myNums = [1, 2, 3, 4, 5, 6, 7, 9];
console.log(getGrouped(myNums));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Off course you can, just return an object containing both evens and odds,
function oddsAndEvens(nums)
{
var evens = [];
var odds = [];
for(var i = 0; i < nums.length; i++){
if(nums[i] % 2 === 0){
evens.push(nums[i])
}
else if (!nums[i] % 2 === 0) {
odds.push(nums[i])
}
}
return {"evens":evens,"odds":odds};
}
var myNums = [1, 2, 3, 4, 5, 6, 7, 9];
result = oddsAndEvens(myNums);
console.log(result.evens);
console.log(result.odds);

Categories

Resources