Recursion in javascript, function restArray - javascript

Anyone can help me? i dont know where is my failure
Implement the restArray function: from an array in which each
position can be a single number or another nested array of numbers,
determine the sum of all numbers contained in the array.
The array will be received by parameter.
Example:
const array = [3, [7, [5,6]], [9,6], 4];
restArray(array); --> It should return 40 and you subtract the result by the number of arrays, not counting the parent.
Example:
40-3 = 37
var restArray = function(array) {
let sum = 0;
if (array.length === 0) {
return -1;
}
for (arr of array) {
if (!Array.isArray(arr)) {
sum += arr;
} else {
sum += restArray(arr);
}
}
return sum;
};
console.log(restArray([3, [7, [5,6]], [9,6], 4]));

Just a minor mistake in your code. As the top level array should not count for subtracting one from the sum, you should not have that case handled in the first if block.
Instead apply that minus one when coming back from recursion, so to account for that nested array:
var restArray = function(array){
let sum = 0;
for (arr of array) {
if (!Array.isArray(arr)) {
sum += arr;
} else {
sum += restArray(arr) - 1;
}
}
return sum;
};
const array = [3, [7, [5,6]], [9,6], 4];
console.log(restArray(array));
It is possible to use reduce to shorten the code a bit and use a bit more functional programming approach:
const restArray = array =>
array.reduce((sum, arr) =>
sum + (Array.isArray(arr) ? restArray(arr) - 1 : arr)
, 0);
const array = [3, [7, [5,6]], [9,6], 4];
console.log(restArray(array));

Related

How to multiply array values without nested loops

Problem:
Given an array of integers, return a new array such that each element at index i of the new array is the product of all the numbers in the original array except the one at i.
For example:
if our input was [1, 2, 3, 4, 5], the expected output would be [120, 60, 40, 30, 24].
If our input was [3, 2, 1], the expected output would be [2, 3, 6].
Solution 1 (With Nested loops): I'm able to solve this by nested loops like below:
const input = [1, 2, 3, 4, 5];
function output(items) {
const finalArray = [];
for (let i = 0; i < items.length; i++) {
let multipliedNum = 1;
items.forEach((item, indx) => {
if (i !== indx) {
multipliedNum = multipliedNum * item;
}
});
finalArray.push(multipliedNum)
}
return finalArray;
}
console.log(output(input))
I'm trying to find out another solution without nested loops inside output function? Any help or suggestion really appreciated.
If there are no zero values, you can loop through all the values once to get the product. Then just return the array where each the product is divided by each entry.
However, if there are zeros then there is a little more to be done to check how many there are. One zero is fine but more than 1 means that the value is zero for each entry.
const input = [1, 2, 3, 4, 5];
const input2 = [1, 2, 3, 4, 0];
const input3 = [1, 2, 3, 0, 0];
function output(items) {
let zeroCount = 0;
let totalProduct = 1;
for (let i = 0; i < items.length; i++) {
if (items[i] === 0) {
if (++zeroCount > 1) break;
continue;
}
totalProduct *= items[i];
}
if (zeroCount > 1) {
// more than 1 zero -> all values are 0
return new Array(items.length).fill(0);
} else if (zeroCount === 1) {
// only 1 zero -> only the value that is zero will be the totalProduct
return items.map(item => item === 0 ? totalProduct : 0);
}
// no zero in array -> divide the totalProduct by each item
return items.map(item => totalProduct / item);
}
console.log(output(input))
console.log(output(input2))
console.log(output(input3))
Based on what #Mike said in the comment here's the answer.
const input = [1, 2, 3, 4, 5];
const mulValues = input.reduce((acc, next) => acc * next);
const output = input.map(i => mulValues/i)
console.log(output)
you can do something like that (assuming array doesn't contain zero):
calculate product of all array elements
divide product by element at position [i] to get the desired output
const input = [1, 2, 3, 4, 5];
function output(items) {
const finalArray = [];
const multipliedNum=1;
for (let i = 0; i < items.length; i++) {
multipliedNum *= item[i];
}
for (let i = 0; i < items.length; i++) {
finalArray.push(multipliedNum/item[i]);
}
return finalArray;
}
console.log(output(input))
I know this has already been answered, but I think I have a better one.
If you take this issue by a different approach you will see that the product leaving the value at the index out, is also the product devided by value at the index.
If you know use the reduce function, you can simply calculate the product in one line using:
items.reduce((a, b) => a * b)
and then just divide by the value you want to ignore... like this:
items.reduce((a, b) => a * b) / items[index]
if you now want to compress this in one line instead of wrapping it into a for loop block you can simply copy the array and use the map function and the result could look like this:
result = [...items].map((v, i) => items.reduce((a, b) => a * b) / v)
I hope that this helps you to reduce your code

How do I sum the elements of an arbitrary number of arrays with different lengths in Javascript?

While the code below will satisfy adding two arrays with different lengths, how can I modify this to accept an arbitrary number of arrays as arguments so that, for example, ([1, 2, 3], [4, 5], [6]) will return an array of [11, 7, 3] ?
const addTogether = (arr1, arr2) => {
let result = [];
for (let i = 0; i < Math.max(arr1.length, arr2.length); i++) {
result.push((arr1[i] || 0) + (arr2[i] || 0))
}
return result
}
Use a nested array, and loop over the array rather than hard-coding two array variables.
You can use arrays.map() to get all the lengths so you can calculate the maximum length. And arrays.reduce() to sum up an element in each array.
const addTogether = (...arrays) => {
let result = [];
let len = Math.max(...arrays.map(a => a.length));
for (let i = 0; i < len; i++) {
result.push(arrays.reduce((sum, arr) => sum + (arr[i] || 0), 0));
}
return result
}
console.log(addTogether([1, 2, 3], [4, 5], [6]));
You can use arguments object inside function.
arguments is an Array-like object accessible inside functions that contains the values of the arguments passed to that function.
const addTogether = function () {
const inputs = [...arguments];
const maxLen = Math.max(...inputs.map((item) => item.length));
const result = [];
for (let i = 0; i < maxLen; i ++) {
result.push(inputs.reduce((acc, cur) => acc + (cur[i] || 0), 0));
}
return result;
};
console.log(addTogether([1,2,3], [4,5], [6]));
Solution:
const addTogether = (...args) => {
let result = [];
let max = 0;
args.forEach((arg)=>{
max = Math.max(max,arg.length)
})
for(let j=0;j<max;j++){
result[j]= 0
for (let i = 0; i < args.length; i++) {
if(args[i][j])
result[j]+= args[i][j]
}
}
return result
}
console.log(addTogether([1, 2, 3], [4, 5], [6]))
Output:[ 11, 7, 3 ]
Use rest param syntax to accept an arbitrary number of arguments. Sort the outer array by their length in descending order. By using destructuring assignment separate the first and rest of the inner arrays. At last use Array.prototype.map() to traverse the first array as it is the largest array and use Array.prototype.reduce() method to get the summation.
const addTogether = (...ar) => {
ar.sort((x, y) => y.length - x.length);
const [first, ...br] = ar;
return first.map(
(x, i) => x + br.reduce((p, c) => (i < c.length ? c[i] + p : p), 0)
);
};
console.log(addTogether([1, 2, 3], [4, 5], [6]));
Instead of using a for loop that requires you to know the lengths of each array, try using something that doesn't. For example - while loop.
Increment using a dummy variable and reset it for each array and set condition for loop termination as - arr[i] === null.

Split array into arrays of numbers where the sum is equal to a specific target

I need to create a function that take as parameter an array and a target. It should return an array of arrays where the sum of these numbers equals to the target
sumPairs(array, target) {
}
For example:
sumPairs([1, 2, 3, 4, 5], 7) // output : [[2, 5], [3, 4]]
I know I have to use map(), and probably reduce(), set(), or filter() maybe (I read their documentation in MDN but still cant find out). I tried some ways but I can't get it.
If you guys could help me to find out how to dynamically create arrays and push them into a new array..
I read there some solutions (Split array into arrays of matching values) but I hate to just use created functions without knowing what they really do or how they work.
Some very basic code for achieving it, Just run all over combinations and conditionally add the items you want.
function sumPairs(array, target) {
var res = [];
for(var i = 0; i < array.length; i++){
for(var j = 0; j < array.length; j++){
if(i!=j && array[i]+array[j]==target &&
res.filter((x)=> x[0] == array[j] && x[1] == array[i]).length == 0 )
res.push([array[i], array[j]]);
}
}
return res;
}
var result = sumPairs([1, 2, 3, 4, 5], 7);
console.log(result);
Option 2 - see this answer for more options (like using reduce)
function sumPairs(array, target) {
return array.flatMap(
(v, i) => array.slice(i+1).filter(w => (v!=w && v+w==target)).map(w=> [w,v])
);
}
var result = sumPairs([1, 2, 3, 4, 5], 7);
console.log(result);
"The exercise says that it sould be arrays of pairs that sum the
target value so I think only 2 items"
If you need a pair that matches a sum and you pick any number from the list, you are left with
the following equation to solve num + x = sum where we want to find x. E.g. if you picked 7 and the target sum is 10 then you know you are looking for a 3.
Therefore, we can first construct a counting map of the numbers available in our list linear (O(n)) time and then search for matches in linear time as well rather than brute forcing with a quadratic algorithm.
const nums = [1, 2, 3, 4, 5];
console.log(findSumPairs(nums, 7));
function findSumPairs(nums, sum) {
const countByNum = countGroupByNum(nums);
return nums.reduce((pairs, num) => {
countByNum[num]--;
const target = sum - num;
if (countByNum[target] > 0) {
countByNum[target]--;
pairs.push([num, target]);
} else {
countByNum[num]++;
}
return pairs;
}, []);
}
function countGroupByNum(nums) {
return nums.reduce((acc, n) => (acc[n] = (acc[n] || 0) + 1, acc), {});
}
Here's another implementation with more standard paradigms (e.g. no reduce):
const nums = [1, 2, 3, 4, 5];
console.log(findSumPairs(nums, 7));
function findSumPairs(nums, sum) {
const countByNum = countGroupByNum(nums);
const pairs = [];
for (const num of nums) {
const target = sum - num; //Calculate the target to make the sum
countByNum[num]--; //Make sure we dont pick the same num instance
if (countByNum[target] > 0) { //If we found the target
countByNum[target]--;
pairs.push([num, target]);
} else {
countByNum[target]++; //Didin't find a match, return the deducted num
}
}
return pairs;
}
function countGroupByNum(nums) {
const countByNum = {};
for (const num of nums) {
countByNum[num] = (countByNum[num] || 0) + 1;
}
return countByNum;
}
You can also sort your array and find all the pairs with given sum by using two pointer method. Place the first pointer to the start of the array and the second pointer to the end.
if the sum of the values at the two places is :
More than target: Decrement your second pointer by 1
Less than target: Increment your first pointer by 1
Equal to target: This is one possible answer, push them to your answer array and increment your first pointer by 1 and decrement your second pointer by 1.
This is more performant solution with complexity O(n*log(n))

How to sum array values with an iterator without a for loop

I want to get the sum of the values of an array only using an iterator function. Below, I get the individual values using an iterator but I'm using a for-loop to ultimately summing their values.
Is there a more elegant way to accomplish the same result using only an iterator function?
function sumArray(arr) {
function nextIterator() {
let i = 0;
var iteratorWithNext = {
next: function nextElement() {
var element = arr[i];
i++
return element;
}
}
return iteratorWithNext;
}
var iteratorWithNext = nextIterator();
let sum = 0;
for (item of arr) {
sum = sum + iteratorWithNext.next();
}
return sum;
}
const array4 = [1, 2, 3, 4];
console.log(sumArray(array4)); // -> 10
If your aim is to take an iterator and sum up all its yielded values, that can easily be done with a simple loop:
function sum(iterator) {
let value, done, sum = 0;
do {
({value, done} = iterator.next());
sum += value || 0;
} while(!done)
return sum;
}
function* iter() { yield 1; yield 2; yield 3; }
sum(iter()) // 6
Yup, this is the example used for reduce.
[1, 2, 3, 4].reduce((sum, number) => sum + number)
The reduce() method applies a function against an accumulator and each element in the array (from left to right) to reduce it to a single value.
Edit: If you want an empty array to evaluate to 0 (rather than error), pass an initial value:
[1, 2, 3, 4].reduce((sum, number) => sum + number, 0)
You can use Array's reduce function to achieve this.
var a = [1, 2, 3, 4];
var sum = a.reduce( (a,b) => a + b);//sum will be 10

Compare 2 or more sorted arrays javascript

I'm trying to handroll a solution for poker. I've gotten all the logic to determine the best 5 card hand. I'm having issues comparing multiple arrays for which have higher elements in the event of ties(with regard to hand type).
Say we have some potential winners for a flush.
var low_flush = [2, 3, 4, 5, 7]
var medium_flush = [3, 4, 5, 6, 8]
var high_flush = [2, 3, 4, 5, 9]
I want to build a function that i pass any number of arrays to and it returns the "highest poker hand" or an array of hands in the event of an actual tie:
function bestHand(hands){
//
return high_hand
}
Everything I've read thus far is how to compare just two arrays, and usually with that, it only sees if there are equal to each other. If it helps heres my source code
My first thoughts are to iterate over the hands. And for each iteration, iterate over the hands again for comparison. Just thinking about this pseudocode is making my head hurt and was thinking their might be a more elegant solution for this and/or library(not a poker library though)
I am using underscore in other parts of the codebase so feel free to use it in answer as well!
You can use reduce() first to count the sum of each array
var total3 = high_flush.reduce(function(previousValue, currentValue) {
return previousValue + currentValue;
}, 0);
after that push each one to an array with total of array and the name of the winner
allhands.push({total: total1 , name: "low_flush"});
then compare them with compare function and sort you array
function compare(a,b) {
if (a.total < b.total)
return -1;
else if (a.total > b.total)
return 1;
else
return 0;
}
allhands.sort(compare);
Working example here:
var low_flush = [2, 3, 4, 5, 7];
var medium_flush = [2, 3, 4, 5, 8];
var high_flush = [2, 3, 4, 5, 9];
var allhands = [];
var total3 = high_flush.reduce(function(previousValue, currentValue) {
return previousValue + currentValue;
}, 0);
allhands.push({total: total3 , name: "high_flush"});
var total1 = low_flush.reduce(function(previousValue, currentValue) {
return previousValue + currentValue;
}, 0);
allhands.push({total: total1 , name: "low_flush"});
var total2 = medium_flush.reduce(function(previousValue, currentValue) {
return previousValue + currentValue;
}, 0);
allhands.push({total: total2 , name: "medium_flush"});
function compare(a,b) {
if (a.total < b.total)
return -1;
else if (a.total > b.total)
return 1;
else
return 0;
}
allhands.sort(compare);
console.log("The winner is "+allhands[allhands.length - 1].name +"With total:"+ allhands[allhands.length - 1].total );
<script src="http://gh-canon.github.io/stack-snippet-console/console.min.js"></script>
This may seem silly. But this seems to work for me.
var hands = [ [2, 3, 4, 5, 7], [2, 3, 5, 9, 8], [2, 3, 4, 5, 9] ];
var values = [];
function bestHand(hands){
hands.forEach(function(arr, index) {
var temp = arr.slice();
values[index] = parseInt(temp.sort().reverse().join(''));
});
var max = Math.max.apply(Math, values);
return hands[values.indexOf(max)];
}
bestHand(hands);
Obviously you need to pass an array of hand objects to something like this.
function getBest(...hands){
return hands.sort((p,c) => p.weight() <= c.weight() ? -1:1)[hands.length-1]
}
when it comes to finding out the weight of a hand object in tie conditions it could be first determined by the hands color (spades beats all) and then by sum of the card values for clubs like 2,3,4,5,6,7,8,9,10,11(j),12(q),13(k),14(a). The sum of them all is 104 so for diamonds card values can be (104+2), (104+3), (104+4) etc.. for hearts you offset values by 208 and for spades by 312.
hand.prototype.weight = function(){
return this.reduce((p,c) => p.value + c.value)
}
Of course this will only handle the tie conditions. It can not tell a flush from a flush royale.
Take a look at array's reduce function here.
Example:
var result = hands.reduce(function(prevHand, currentHand) {
return compareHands(prevHand,currentHand) ? prevHand : currentHand;
});
This answers the question about comparing multiples arrays, but keep in mind that it will reduce it to one value, this may not be the perfect solution since you have to consider draws. In that case your result should be an array, and in the comparison push into the array or reinitialize and add it to the array.
function bestHands(DescOrderedHands){
bestHand = DescOrderedHands[0]
bestHandScore = parseInt(_.map(bestHand, function(num){return num.toString}).join(""))
_.each(DescOrderedHands, function(hand){
stringHand = _.map(hand, function(num){return num.toString}).join("")
if (parseInt(stringHand) > bestHandScore){
bestHand = hand
}
}
return bestHand
}
First, You have to be sure that all arrays in your your function have the same length, then you have to sort each array, and finally you have to compare each value of each array.
You should have something like this
function bestHand(hands){
var best_hand = null;
for(var i = 0; i < hands.length; ++i){
hands[i] = hands[i].sort();
if(i > 0){
for(var j = 0; j < hands[i].length; ++j){
if(best_hand[j] < hands[i][j]){
best_hand = hands[i];
break;
}
else if(best_hand[j] > hands[i][j]){
break;
}
}
}
else{
best_hand = hands[i];
}
}
return best_hand;
}
Be sure you pass arrays with the same length in argument

Categories

Resources