Array Reduce Sum Using Recursion - javascript

Given an array of length n, consolidate the sum created by adding index pairs until there's only a single index.
EXAMPLES:
[1, 2, 3, 4, 5] => 48
Explanation:
The next array would be [3, 5, 7, 9] because [1+2, 2+3, 3+4, 4+5]
The next array would be [8, 12, 16] because [3+5, 5+7, 7+9]
The next array would be [20, 28] because [8+12, 12+16]
The final answer would be [48] because [20+28] and there are not enough operands to add
This is the solution I came up with but I feel like there's a simpler way to achieve the same solution. I'm trying to understand recursion but I need some explanation on why when we call our stacks, we do it from the (n - 1) or from the (n + 1) to reach our base cases and how do we know which one to use? I don't understand why we're using those passing arguments when we are returning our helper function.
function reduceSum(input) {
function simplify(input, index) {
if (index === 1) {
return input[0];
}
if (index === 0) {
return 0;
}
for (let i = 0; i < input.length; i++) {
input[i] += input[i + 1];
}
return simplify(input, index - 1);
}
return simplify(input, input.length);
}
console.log(reduceSum([1, 2, 3, 4]) == 20)
console.log(reduceSum([5]) == 5)
console.log(reduceSum([]) == 0)
console.log(reduceSum([1, 3, 5]) == 12)
console.log(reduceSum([-5, 5]) == 0)
console.log(reduceSum([-5, 5, -5, 5]) == 0)
console.log(reduceSum([-5, 5, 5, -5]) == 20)

I'm not sure the following is a genuinely simpler way to achieve the solution as it does basically the same thing (although it does not modify the original array), but perhaps there's something useful here:
function reduceSum(input) {
if(input.length <= 1)
return input[0] || 0;
return reduceSum(
input.reduce(
(acc, val, i, { [i + 1]: next }) =>
typeof next !== 'undefined' ? [ ...acc, val + next ] : acc,
[]
)
);
}
console.log(reduceSum([1, 2, 3, 4]) == 20)
console.log(reduceSum([5]) == 5)
console.log(reduceSum([]) == 0)
console.log(reduceSum([1, 3, 5]) == 12)
console.log(reduceSum([-5, 5]) == 0)
console.log(reduceSum([-5, 5, -5, 5]) == 0)
console.log(reduceSum([-5, 5, 5, -5]) == 20)
The next variable is populated using object destructuring on the array argument passed to the reduce callback function. It will be undefined when the reduce method processes the last element of the array, this last element gets skipped; this means that each time we run reduceSum the array gets shorter by one element (as per your original).

Each loop updates values in the array. And with each loop the index needs to be reduced, otherwise it will be infinite loop. Just add console.log("" + input) right after the for loop and you'll see how input progresses with each call of simplify() function.
There are a few optimizations can be done to your code:
you don't need simplify() at all, simply check if index variable is undefined:
function reduceSum(input, index) {
if (index === undefined)
index = input.length;
if (index === 1) {
return input[0];
}
if (index === 0) {
return 0;
}
for (let i = 0; i < input.length; i++) {
input[i] += input[i + 1];
}
console.log("input: " + input);
return reduceSum(input, index - 1);
}
console.log("result:", reduceSum([1, 2, 3, 4, 5]) == 48)
console.log("result:", reduceSum([1, 2, 3, 4]) == 20)
console.log("result:", reduceSum([5]) == 5)
console.log("result:", reduceSum([]) == 0)
console.log("result:", reduceSum([1, 3, 5]) == 12)
console.log("result:", reduceSum([-5, 5]) == 0)
console.log("result:", reduceSum([-5, 5, -5, 5]) == 0)
console.log("result:", reduceSum([-5, 5, 5, -5]) == 20)
You can also optimize a little by only looping through 0 to index - 1 instead of entire array:
function reduceSum(input, index) {
if (index === undefined)
index = input.length;
if (index === 1) {
return input[0];
}
if (index === 0) {
return 0;
}
for (let i = 0; i < index - 1; i++) {
input[i] += input[i + 1];
}
console.log("input: " + input);
return reduceSum(input, index - 1);
}
console.log("result:", reduceSum([1, 2, 3, 4, 5]) == 48)
console.log("result:", reduceSum([1, 2, 3, 4]) == 20)
console.log("result:", reduceSum([5]) == 5)
console.log("result:", reduceSum([]) == 0)
console.log("result:", reduceSum([1, 3, 5]) == 12)
console.log("result:", reduceSum([-5, 5]) == 0)
console.log("result:", reduceSum([-5, 5, -5, 5]) == 0)
console.log("result:", reduceSum([-5, 5, 5, -5]) == 20)
Further you can optimize the code by adding default value to the index variable and moving conditions to the end the function, this way it won't need an extra call of the function to get final result:
function reduceSum(input, index = input.length - 1) {
for (let i = 0; i < index; i++) {
input[i] += input[i + 1];
}
console.log("input: " + input);
if (index > 1)
return reduceSum(input, --index);
//return final result or 0 if array is empty
return input[0] || 0;
}
console.log("result:", reduceSum([1, 2, 3, 4, 5]) == 48)
console.log("result:", reduceSum([1, 2, 3, 4]) == 20)
console.log("result:", reduceSum([5]) == 5)
console.log("result:", reduceSum([]) == 0)
console.log("result:", reduceSum([1, 3, 5]) == 12)
console.log("result:", reduceSum([-5, 5]) == 0)
console.log("result:", reduceSum([-5, 5, -5, 5]) == 0)
console.log("result:", reduceSum([-5, 5, 5, -5]) == 20)
Finally, you can get rid of index all together, by removing last item from the input array instead, this method is slower than the above though:
function reduceSum(input) {
for (let i = 0; i < input.length - 1; i++) {
input[i] += input[i + 1];
}
console.log("input: " + input);
if (input.length > 1)
{
//remove last item by reducing length of the array
input.length--;
return reduceSum(input);
}
//return final result or 0 if array is empty
return input[0] || 0;
}
console.log("result:", reduceSum([1, 2, 3, 4, 5]) == 48)
console.log("result:", reduceSum([1, 2, 3, 4]) == 20)
console.log("result:", reduceSum([5]) == 5)
console.log("result:", reduceSum([]) == 0)
console.log("result:", reduceSum([1, 3, 5]) == 12)
console.log("result:", reduceSum([-5, 5]) == 0)
console.log("result:", reduceSum([-5, 5, -5, 5]) == 0)
console.log("result:", reduceSum([-5, 5, 5, -5]) == 20)

You can use a for loop as follows:
function reduceSum(input) {
if( input.length < 2 ) {
return input[0] || 0;
}
const arr = [];
for(let i = 0; i < input.length - 1; i++) {
arr.push(input[i] + input[i+1]);
}
return reduceSum( arr );
}
console.log(reduceSum([1, 2, 3, 4]) == 20)
console.log(reduceSum([5]) == 5)
console.log(reduceSum([]) == 0)
console.log(reduceSum([1, 3, 5]) == 12)
console.log(reduceSum([-5, 5]) == 0)
console.log(reduceSum([-5, 5, -5, 5]) == 0)
console.log(reduceSum([-5, 5, 5, -5]) == 20)

Related

Swapping array with alternative numbers

In an array take alternate numbers and swap them. Put it again in the place of array again
e.g., arr = [8,7,4,6,9,3,2,1]
newarr= [8,1,4,3,9,6,2,7]
The Code which I tried is below one
let arr = [8, 7, 4, 6, 9, 3, 2, 1];
let data = arr.map((val, index, curr) => {
if (index == 0) {
return curr[index];
} else if (index == 1) {
return curr[7];
} else if (index == 2) {
return curr[index];
} else if (index == 3) {
return curr[5];
} else if (index == 4) {
return curr[index];
} else if (index == 5) {
return curr[3];
} else if (index == 6) {
return curr[index];
} else if (index == 7) {
return curr[1];
}
});
console.log(data);
This is not the correct way to proceed.
When you consider every odd indexed element to be alternate -
let arr = [8, 7, 4, 6, 9, 3, 2, 1];
let lastAlternate = arr.length % 2 == 0 ? arr.length : arr.length - 1;
let data = arr.map((val, index, curr) => {
if (index % 2 == 0) {
return curr[index];
} else {
return curr[lastAlternate - index];
}
});
console.log(data);

Use recursion on array [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
Write a function that by given array of integers, and a positive number X, returns
the product of all odd elements that are greater than X. Use recursion!
I tried this:
function result(arr, x) {
if (arr.length <= 0) {
return 0;
}
if (arr[0] > x && arr[0] % 2 === 1) {
return arr[0] + result(arr.slice(1));
}
return result(arr.slice(1));
}
console.log(result([3, 2, 3, 4, 5, 6, 7, 8, 9], 1));
And the answer is 3.
After the first iteration (x becomes undefined).
Try like this:
function result(arr, x) {
if (arr.length <= 0) {
return 0;
}
if (arr[0] > x && arr[0] % 2 === 1) {
return arr[0] + result(arr.slice(1), x);
}
return result(arr.slice(1), x);
}
console.log(result([3, 2, 3, 4, 5, 6, 7, 8, 9], 1));
You were very close! You only needed to pass the value of x into the result function when calling it again. After that, it returns the correct answer: 3 + 3 + 5 + 7 + 9 = 27
EDIT: x needs to be passed into the function call each time because of the scope of the variables. So far, the result function only knows about the variables passed directly into it.
If x is a constant, another way to deal with that would be to define x at the beginning and then change the function to only accept the array:
const x = 1;
function result(arr) {
if (arr.length <= 0) {
return 0;
}
if (arr[0] > x && arr[0] % 2 === 1) {
return arr[0] + result(arr.slice(1));
}
return result(arr.slice(1));
}
console.log(result([3, 2, 3, 4, 5, 6, 7, 8, 9]));
If x is not a constant, but you only want to pass the value into a recursive function once, you can do that too with a sub-function, e.g.:
function result(arr, x) {
function recur(arr) {
if (arr.length <= 0) {
return 0;
}
if (arr[0] > x && arr[0] % 2 === 1) {
return arr[0] + recur(arr.slice(1));
}
return recur(arr.slice(1));
}
return recur(arr);
}
console.log(result([3, 2, 3, 4, 5, 6, 7, 8, 9], 1));
In this case, the recur function can access the variables passed directly into it (arr) as well as the variables of its parent function (x). The value of arr of the closest available scope is used. This method can be helpful in simplifying complicated recursive functions.
You are trying to calculate the sum. The product of the odd numbers from [3, 2, 3, 4, 5, 6, 7, 8, 9] > 1 would imho be: 3 * 3 * 5 * 7 * 9 (= 2835). Here's a snippet that filters out the odd numbers > 1 first, than uses a recursive (sub) function to calculate the product. The use of the sub function is an optimization. You can also use Array.reduce btw.
function productOfUnEvenValuesGreaterThanX(arr, x) {
// filter desired values
const oddAndGreaterThanX = arr.filter(v => v > x && ~~(v % 2));
// ^ bitwise to determine odd
// calculate the product recursively
function product(arrx, y) {
return arrx.length
? product(arrx.slice(1), (arrx.shift() || 1) * y)
: y;
}
return !oddAndGreaterThanX.length ? 0 : product(oddAndGreaterThanX, x);
}
console.log(productOfUnEvenValuesGreaterThanX([3, 2, 3, 4, 5, 6, 7, 8, 9], 1));
console.log(productOfUnEvenValuesGreaterThanX([2, 4, 6, 8], 1));
// alternatively you can use a reducer
function productOfUnEvenValuesGreaterThanXReducer(arr, x) {
return arr.reduce( (acc, val) =>
val > x && ~~(val % 2)
? (acc || 1) * val
: acc, 0 );
}
console.log(productOfUnEvenValuesGreaterThanXReducer([3, 2, 3, 4, 5, 6, 7, 8, 9], 1));
console.log(productOfUnEvenValuesGreaterThanXReducer([2, 4, 6, 8], 1));
Another recursive approach without mutating the array.
function sumResult(arr, x, i = 0, sum = 0) {
if ([0, i].includes(arr.length)) {
return sum;
}
const updated = sum + (arr[i] > x && arr[i] % 2 === 1 ? arr[i] : 0);
return sumResult(arr, x, i + 1, updated);
}
console.log('sum: ', sumResult([3, 2, 3, 4, 5, 6, 7, 8, 9], 1));
function productResult(arr, x, i = 0, product = 1) {
if ([0, i].includes(arr.length)) {
return product;
}
const updated = product * (arr[i] > x && arr[i] % 2 === 1 ? arr[i] : 1);
return productResult(arr, x, i + 1, updated);
}
console.log('product: ', productResult([3, 2, 3, 4, 5, 6, 7, 8, 9], 1));

Return value in Javascript function (Sum of number divided by 3)

I my task is to call this function and return value of sum of all number in array that can be divided by 3. The problem is that I do not know how to make return value of the function in JS. Can You please help?
Thank You
function sumNumbersBy3(...numberArray) {
for(let i = 0; i < numberArray.length; i++)
{
if (numberArray[i]%3 == 0)
return
}
}
console.log("sumNumbersBy3", sumNumbersBy3(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) === 18);
You should have a variable to sum numbers which satisfies condition numberArray[i] % 3 == 0:
function sumNumbersBy3(numberArray) {
let sum = 0
for(let i = 0; i < numberArray.length; i++)
{
if (numberArray[i] % 3 == 0)
sum += numberArray[i];
}
return sum;
}
In addition, you can use reduce method:
const result = arr.reduce((a, c, i) => {
(c % 3 == 0) ? a += c : 0;
return a;
}, 0);
An example:
function sumNumbersBy3(numberArray) {
let sum = 0
for(let i = 0; i < numberArray.length; i++)
{
if (numberArray[i] % 3 == 0)
sum += numberArray[i];
}
return sum;
}
console.log("sumNumbersBy3: ", sumNumbersBy3([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]));
let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const result = arr.reduce((a, c, i) => {
(c % 3 == 0) ? a += c : 0;
return a;
}, 0);
console .log(`Using reduce method: ${result}`);
function sumNumbersBy3(...numberArray) {
let sum = 0;
for (let i = 0; i < numberArray.length; i++) {
if (numberArray[i] % 3 == 0)
sum += numberArray[i];
}
return sum;
}
console.log("sumNumbersBy3", sumNumbersBy3(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));

How to divide an array to chunks with flexible output length?

How to divide an array to chunks with flexible output length?
it's necessary for render pagination, where we have limited place for elements,
and if we have several pages of elements — we need to display buttons with arrays (prev/next) instead el's.
example f() input-output, when 1st argument is Array with data,
and 2nd arg is maximum of elements in list, including nav-buttons:
f([1,2,3,4], 4) => [1,2,3,4]
f([1,2,3,4,5], 4) => [[1,2,3], [4,5]]
f([1,2,3,4,5,6], 4) => [[1,2,3], [4,5,6]]
f([1,2,3,4,5,6,7], 4) => [[1,2,3], [4,5], [6,7]]
f([7,6,5,4,3,2,1], 4) => [[7,6,5], [4,3], [2,1]]
f([1,2,3,4,5,6,7], 6) => [[1,2,3,4,5], [6,7]]
Example of design-layout with max 6 elements
1st page:
2nd page:
Last page:
First, determine if one page/two pages are enough. If not, loop the array.
let f = (array, max) => {
if (array.length / max <= 1)
return array
if (array.length / (max - 1) <= 2)
return [array.slice(0, max - 1), array.slice(max - 1, array.length)]
let result = []
let n = 0
while (n <= array.length - 1) {
if (n == 0) {
result.push(array.slice(n, n + max - 1))
n += max - 1
} else {
let pushAmount = n+max-1 >= array.length ? max-1 : max-2
result.push(array.slice(n, n + pushAmount))
n += pushAmount
}
}
return result
}
console.log(f([1, 2, 3, 4], 4))
console.log(f([1, 2, 3, 4, 5], 4))
console.log(f([1, 2, 3, 4, 5, 6], 4))
console.log(f([1, 2, 3, 4, 5, 6, 7], 4))
console.log(f([7, 6, 5, 4, 3, 2, 1], 4))
console.log(f([1, 2, 3, 4, 5, 6, 7], 6))
I hope this will work !
a=[1,2,3,4,5,6,7,8,9,2];
result=[];
start = true;
function f(arr,n){
if(arr.length >= n-2){
console.log(start)
if(start){
start=false;
result.push(arr.splice(0,n-1))
return f(arr,n)
}else{
result.push(arr.splice(0,n-2))
return f(arr,n)
}
} else {
result.push(arr);
return 1;
}
}
f(a,6);
console.log(result)
Another solution - with recursion. I felt this was a bit easier to understand.
f = (arr, max, first = true) => {
if (arr.length == 0) return []
const last = arr.length <= max - !first
const curLen = max - !first - !last
const cur = arr.slice(0, curLen)
const next = f(arr.slice(curLen), max, false)
return [cur, ...next]
}
console.log(f([1, 2, 3, 4], 4))
console.log(f([1, 2, 3, 4, 5], 4))
console.log(f([1, 2, 3, 4, 5, 6], 4))
console.log(f([1, 2, 3, 4, 5, 6, 7], 4))
console.log(f([7, 6, 5, 4, 3, 2, 1], 4))
console.log(f([1, 2, 3, 4, 5, 6, 7], 6))

Finding the local maxima in a 1D array

Is there an easy way to find the local maxima in a 1D array?
Let's say I have an array:
[ 0,
1,
10, <- max
8, <- (ignore)
3,
0,
0,
4,
6, <- (ignore)
10, <- max
6, <- (ignore)
1,
0,
0,
1,
4, <- max
1,
0 ]
I want it to find the 10s and the 4, but ignore the 8 & 6, since those are next to 10s. Mathematically, you could just find where derivative is equal to zero if it were a function. I'm not too sure how to do this in Javascript.
This will return an array of all peaks (local maxima) in the given array of integers, taking care of the plateaus as well:
function findPeaks(arr) {
var peak;
return arr.reduce(function(peaks, val, i) {
if (arr[i+1] > arr[i]) {
peak = arr[i+1];
} else if ((arr[i+1] < arr[i]) && (typeof peak === 'number')) {
peaks.push(peak);
peak = undefined;
}
return peaks;
}, []);
}
findPeaks([1,3,2,5,3]) // -> [3, 5]
findPeaks([1,3,3,3,2]) // -> [3]
findPeaks([-1,0,0,-1,3]) // -> [0]
findPeaks([5,3,3,3,4]) // -> []
Note that the first and last elements of the array are not considered as peaks, because in the context of a mathematical function we don't know what precedes or follows them and so cannot tell if they are peaks or not.
maxes = []
for (var i = 1; i < a.length - 1; ++i) {
if (a[i-1] < a[i] && a[i] > a[i+1])
maxes.push(a[i])
}
This code finds local extrema (min and max, where first derivation is 0, and ), even if following elements will have equal values (non-unique extrema - ie. '3' is choosen from 1,1,1,3,3,3,2,2,2)
var GoAsc = false; //ascending move
var GoDesc = false; //descending move
var myInputArray = [];
var myExtremalsArray = [];
var firstDiff;
for (index = 0; index < (myArray.length - 1); index++) {
//(myArray.length - 1) is because not to exceed array boundary,
//last array element does not have any follower to test it
firstDiff = ( myArray[index] - myArray[index + 1] );
if ( firstDiff > 0 ) { GoAsc = true; }
if ( firstDiff < 0 ) { GoDesc = true; }
if ( GoAsc === true && GoDesc === true ) {
myExtremalsArray.push(myArray[index]);
GoAsc = false ;
GoDesc = false;
//if firstDiff > 0 ---> max
//if firstDiff < 0 ---> min
}
}
The two situations are when you have a peak, which is a value greater than the previous and greater than the next, and a plateau, which is a value greater than the previous and equal to the next(s) until you find the next different value which must me less.
so when found a plateau, temporary create an array from that position 'till the end, and look for the next different value (the Array.prototype.find method returns the first value that matches the condition ) and make sure it is less than the first plateau value.
this particular function will return the index of the first plateau value.
function pickPeaks(arr){
return arr.reduce( (res, val, i, self) => {
if(
// a peak when the value is greater than the previous and greater than the next
val > self[i - 1] && val > self[i + 1]
||
// a plateau when the value is greater than the previuos and equal to the next and from there the next different value is less
val > self[i - 1] && val === self[i + 1] && self.slice(i).find( item => item !== val ) < val
){
res.pos.push(i);
res.peaks.push(val);
}
return res;
}, { pos:[],peaks:[] } );
}
console.log(pickPeaks([3,2,3,6,4,1,2,3,2,1,2,3])) //{pos:[3,7],peaks:[6,3]}
console.log(pickPeaks([-1, 0, -1])) //{pos:[1],peaks:[0]}
console.log(pickPeaks([1, 2, NaN, 3, 1])) //{pos:[],peaks:[]}
console.log(pickPeaks([1, 2, 2, 2, 1])) //{pos: [1], peaks: [2]} (plateau!)
How about a simple iteration?
var indexes = [];
var values = [0,1,10,8,3,0,0,4,6,10,6,1,0,0,1,4,1,0];
for (var i=1; i<values.length-1; i++)
if (values[i] > values[i-1] && values[i] > values[i+1])
indexes.push(i);
more declarative approach:
const values = [3, 2, 3, 6, 4, 1, 2, 3, 2, 1, 2, 3];
const findPeaks = arr => arr.filter((el, index) => {
return el > arr[index - 1] && el > arr[index + 1]
});
console.log(findPeaks(values)); // => [6, 3]
A Python implementation, with a couple of points
Avoids using a reduce to make it easier to see the algorithm
First and last items are considered peaks (this can be a requirement, e.g. in interviews)
All values in the plateau are added
Can start or end on an plateau
def findPeaks(points: List[int]) -> List[int]:
peaks, peak = [], []
if points[0] >= points[1]: # handle first
peak.append(points[0])
for i in range(1, len(points)):
prv = points[i - 1]
cur = points[i]
if cur > prv: # start peak
peak = [cur]
elif cur == prv: # existing peak (plateau)
peak.append(cur)
elif cur < prv and len(peak): # end peak
peaks.extend(peak)
peak = []
if len(peak) and len(peak) != len(points): # ended on a plateau
peaks.extend(peak)
return peaks
if __name__ == "__main__":
print(findPeaks([1, 2, 3, 4, 5, 4, 3, 2, 1])) # [5]
print(findPeaks([1, 2, 1, 2, 1])) # [2, 2]
print(findPeaks([8, 1, 1, 1, 1, 1, 9])) # [0, 6]
print(findPeaks([1, 1, 1, 1, 1])) # []
print(findPeaks([1, 6, 6, 6, 1])) # [6, 6, 6]
const values = [3, 2, 3, 6, 4, 1, 2, 3, 2, 1, 2, 3];
const findMinimas = arr => arr.filter((el, index) => {
return el < arr[index - 1] && el < arr[index + 1]
});
console.log(findMinimas(values)); // => [2, 1, 1]
const findMinimumIndices = arr => arr.map((el, index) => {
return el < arr[index - 1] && el < arr[index + 1] ? index : null
}).filter(i => i != null);
console.log(findMinimumIndices(values)); // => [1, 5, 9]

Categories