Strange behaviour of reduce method in JavaScript? - javascript

I was trying to create an even number array of Fibonacci series using Functional Programming - below code
let a = [1, 2];
const r = (n) =>
Array.from(
a[a.length - 1] + a[a.length - 2] <= n ?
a.push(a[a.length - 1] + a[a.length - 2]) && r(n) :
a
)
.filter(v => !(v % 2))
//.reduce((s, v) => s+=v, 0)
console.log(r(56))
It is giving correct array but when I wanted to calculate the sum (using reduce method by commenting the last line) it is giving 0 as a result
let a = [1, 2];
const r = (n) =>
Array.from(
a[a.length - 1] + a[a.length - 2] <= n ?
a.push(a[a.length - 1] + a[a.length - 2]) && r(n) :
a
)
.filter(v => !(v % 2))
.reduce((s, v) => s+=v, 0)
console.log(r(56))
in Repl.it (Link - https://repl.it/#rahul4sap/1). However, when I try to paste the same in Chrome Dev tools it is giving correct output. Can someone please help me explain why different behavior in Chrome Dev tool and Repl.it (same behaviour I see in local Node server)
Also, it will be good if someone please help me in fixing this as well (Please note I wanted to solve this in as much Functional way as possible)
Thanks in advance!

You could separate the functions an dget the fibonacci array first and then filter the array, and so on.
This approach uses a recursion by handing over a new build array.
const
add = (a, b) => a + b,
f = (n, a = [1, 2]) => a[a.length - 1] + a[a.length - 2] < n
? f(n, [...a, a[a.length - 1] + a[a.length - 2]])
: a,
r = n => f(n)
.filter(v => !(v % 2))
.reduce(add, 0);
console.log(r(56));

Consider a simple recursive function, fibs -
const fibs = (n = 0, a = 0, b = 1) =>
n <= 0
? []
: [ a, ...fibs(n - 1, b, a + b) ]
console.log(fibs(10)) // first 10 fib numbers
// [ 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 ]
Now add your .filter -
const fibs = (n = 0, a = 0, b = 1) =>
n <= 0
? []
: [ a, ...fibs(n - 1, b, a + b) ]
const evens =
fibs(10)
.filter(n => !(n & 1))
console.log(evens)
// [ 0, 2, 8, 34 ]
Now add your .reduce -
const fibs = (n = 0, a = 0, b = 1) =>
n <= 0
? []
: [ a, ...fibs(n - 1, b, a + b) ]
const sumEvens =
fibs(10)
.filter(n => !(n & 1))
.reduce((r, n) => r + n, 0)
console.log(sumEvens)
// 44
To see how you can compute fibonacci using other functional programming techniques, see this recent Q&A
Thank you for this. But I am looking for pushing element in an array (probably in a single function) until certain condition is met (like create Fibbonacci array until the last element is less than 100).
You change n = 0 to until = 0 and change the exit condition of your loop from n <= 0 to a > until -
const fibs = (until = 0, a = 0, b = 1) =>
a > until
? []
: [ a, ...fibs(until, b, a + b) ]
console.log(fibs(100))
// [ 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89 ]
const sumEvens =
fibs(100)
.filter(n => !(n & 1))
.reduce((r, n) => r + n, 0)
console.log(sumEvens)
// 4

You may receive result in one line when you know how many fibonacci numbers do you need.
For example this code filter even numbers from the first 10 fibonacci numbers and calculate their sum:
let arr = (n) => [1, 2, ...Array(n-2)].reduce((acc, rec, idx) => (idx < 2) ? [...acc, rec] : [...acc, (acc[idx-2] + acc[idx-1])],[])
.filter(it => !(it % 2))
.reduce((s, v) => s+=v, 0)
console.log(arr(10))

Related

Create a list of results of all recursive calls performed by a function call

I want to achieve the same result I can get with this code:
function fibs(n) {
let fibs = []
for (let i = 0; i <= n; i++) {
if ((i <= 1)) fibs.push(i)
else fibs.push(fibs[i - 1] + fibs[i - 2])
}
return fibs
}
console.log( fibs(8) )
with a recursive function.
Obviously, when you console.log(fibs(8) it renders a list like this: [0, 1, 1, 2, 3, 5, 8, 13, 21]
My recursive function looks like this:
function fibsRec(n) {
if (n < 2) return n
return fibsRec(n - 1) + fibsRec(n - 2)
}
console.log( fibsRec(8) )
and if you console.log(fibsRec(8)) it returns 21, which is the 8th Fibonacci number, but doesn't give me the list of all the Fibonacci numbers before it. How can I get the list without a loop, just from my recursive function?
How can I get the same outcome as fibs() with fibsRec()
where it goes wrong
Let's review. If fibsRec is meant to return an array, we can first notice that return n isn't going to work. n is just a number and we need an array.
function fibsRec(n) {
if (n < 2) return n // <- problem one
return fibsRec(n - 1) + fibsRec(n - 2) // <- problem two
}
Second, if fibsRec is going to be returning arrays, we cannot simply call + for fibsRec(n - 1) and fibsRec(n - 2). Watch what happens if we were to try -
const a = [1,2,3]
const b = [4,5,6]
console.log(a + b) // 1,2,34,5,6
Maybe you're thinking that's an odd result. Really JavaScript should throw an error for such misuse of +, but instead it tries its "best" to perform the addition. To do so, it coerces each array to a string first, then combines the strings together -
const a = [1,2,3]
const b = [4,5,6]
console.log(String(a)) // 1,2,3
console.log(String(b)) // 4,5,6
console.log(a + b) // 1,2,34,5,6
behaviour-oriented design
To understand how fibsRec needs to behave, let's first define some outputs for known inputs -
f(n)
output
f(0)
[]
f(1)
[0]
f(2)
[0,1]
f(3)
[0,1,1]
f(4)
[0,1,1,2]
f(5)
[0,1,1,2,3]
f(6)
[0,1,1,2,3,5]
...
...
To fix the first problem, easy mode, change return n to return a range 0..n instead -
function fibsRec(n) {
if (n < 2) return range(0,n) // <- fix one
return fibsRec(n - 1) + fibsRec(n - 2) // ...
}
const range = (a, b) =>
a >= b
? []
: [a, ...range(a + 1, b)]
you can't + arrays, but you can fibplus them...
To fix the second problem, we need a function that can "add" fibonacci sequences (arrays) because + just isn't going to cut it. We'll call our function fibplus -
function fibsRec(n) {
if (n < 2) return range(0,n)
return fibplus(fibsRec(n - 1), fibsRec(n - 2)) // <- fix two
}
We just have to define how fibplus will add the sequences to achieve the correct result. Let's work off an example. To compute fib(6) we need to "add" fib(5) and fib(4). We could just try stacking the two sequences and adding down to get the result -
0 1 1 2 3 == fib(4)
+ 0 1 1 2 3 5 == fib(5)
------------------------------------
0 1 2 3 5 8 ~~ fib(6)
It's very close to fib(6) but notice it's off by one. Watch what happens when we prepend a 1 to the smaller number before adding -
1 -> 1 0 1 1 2 3
+ 0 1 1 2 3 5
------------------------------------
1 1 2 3 5 8 ~~ fib(6)
Now if we prepend a 0 to the sum ...
1 0 1 1 2 3
+ 0 1 1 2 3 5
------------------------------------
0 -> 0 1 1 2 3 5 8 == fib(6)
We now have fib(6)! We just need to write fibplus to implement this adding technique -
const fibplus = (a, b) =>
[0, ...zip(add, a, [1, ...b])]
const zip = (f, a, b) =>
a.map((v, i) => f(v, b[i]))
const add = (a, b) => a + b
functioning demo
Run the snippet below to verify the result in your own browser -
const fib = n =>
n < 2
? range(0, n)
: fibplus(fib(n - 1), fib(n - 2))
const range = (a, b) =>
a >= b
? []
: [a, ...range(a + 1, b)]
const fibplus = (a, b) =>
[0, ...zip(add, a, [1, ...b])]
const zip = (f, a, b) =>
a.map((v, i) => f(v, b[i]))
const add = (a, b) => a + b
console.log(String(fib(20)))
0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181
visualizing
So indeed we were able to make fibsRec work using fibplus, but by mirroring the original recursive process we inherited a lot of inefficiency as well. We can see the sheer amount of duplicated work -
#WillNess comments below and explains another way fibplus can be rewritten to save some work, but the real drawback of the approach above is the resulting exponential process. Let's see some other ways to get the result we are looking for.
other processes
I like the way you asked the question: "How can I get the same outcome?". Different procedures evolve different processes, and we are not required to create a recursive branching process. Instead a linear iterative process is more efficient and better suited for the desired output.
Note fibs returns an array, but I cast the output as a string for more digestible output -
const fibs = (n, a = 0, b = 1) =>
n <= 0
? []
: [a, ...fibs(n - 1, b, a + b)]
console.log(String(fibs(10)))
So how does it work? Recursion is a functional heritage and so using it with functional style yields the best results. This means avoiding things like mutation, variable reassignments, or other side effects. When a function is referentially transparent, its call can be replaced by its return value, without changing the meaning of our program.
fibs(6)
== fibs(6, 0, 1)
== [0, ...fibs(5, 1, 1)]
== [0, ...[1, ...fibs(4, 1, 2)]]
== [0, ...[1, ...[1, ...fibs(3, 2, 3)]]]
== [0, ...[1, ...[1, ...[2, ...fibs(2, 3, 5)]]]]
== [0, ...[1, ...[1, ...[2, ...[3, ...fibs(1, 5, 8)]]]]]
== [0, ...[1, ...[1, ...[2, ...[3, ...[5, ...fibs(0, 8, 13)]]]]]]
== [0, ...[1, ...[1, ...[2, ...[3, ...[5, ...[]]]]]]]
== [0, ...[1, ...[1, ...[2, ...[3, ...[5]]]]]]
== [0, ...[1, ...[1, ...[2, ...[3, 5]]]]]
== [0, ...[1, ...[1, ...[2, 3, 5]]]]
== [0, ...[1, ...[1, 2, 3, 5]]]
== [0, ...[1, 1, 2, 3, 5]]
== [0, 1, 1, 2, 3, 5]
wasteful intermediate arrays
You might notice that the many intermediate arrays is somewhat wasteful and the result could be accomplished with a single array. Let's make a push helper to do just that -
const push = (arr, val) =>
(arr.push(val), arr)
const fibs = (n, a = 0, b = 1, r = []) =>
n == 0
? r
: fibs(n - 1, b, a + b, push(r, a))
console.log(String(fibs(10)))
Let's see how this one works -
fibs(6)
== fibs(6, 0, 1, [])
== fibs(5, 1, 1, [0])
== fibs(4, 1, 2, [0,1])
== fibs(3, 2, 3, [0,1,1])
== fibs(2, 3, 5, [0,1,1,2])
== fibs(1, 5, 8, [0,1,1,2,3])
== fibs(0, 8, 11, [0,1,1,2,3,5])
== [0,1,1,2,3,5]
streams
Another fun way to calculate sequences of fibonacci numbers is to use streams. Streams deliver data over time as it is needed, instead of all at once. Because streams allow us to consume only as much as need, we can actually define fibs as an infinite stream. Notice it is no longer a function -
const fibs =
stream(0, _ =>
stream(1, _ =>
streamAdd(fibs, fibs.next)))
The building blocks of our streams are emptyStream and stream. To construct a non-empty stream, we give provide any value to stream and a thunk _ => ... where ... is computation of the next value, if any -
const emptyStream =
Symbol('emptyStream')
const stream = (value, next) => ({
value,
get next() { delete this.next; return this.next = next() }
})
Streams as defined here are not the same as JavaScript's built-in generators. The primary difference is they are persistent, meaning they can be replayed any number of times. JavaScript's generators have an internal "cursor" and once it advances, you can never rewind it. This is important for our fibs stream because you can see it consumes itself twice. If we used generators, advancing the generator for one operation would permanently advance it for all others.
Next we define generic stream operations. streamAdd combines two streams of numbers using addition -
const streamAdd = (s1, s2) =>
s1 === emptyStream || s2 === emptyStream
? emptyStream
: stream(s1.value + s2.value, _ => streamAdd(s1.next, s2.next))
And because fibs is infinite, we need some way to limit how much we bite off. streamTake will terminate an infinite stream after that limit is reached -
const streamTake = (s = emptyStream, n = 0) =>
s === emptyStream || n <= 0
? emptyStream
: stream(s.value, _ => streamTake(s.next, n - 1))
Finally, to fulfill the desired output, we convert the finite stream to an array -
function streamToArray(s = emptyStream) {
const r = []
while (s != emptyStream) {
r.push(s.value)
s = s.next
}
return r
}
Run the stream demo below to verify the result in your browser -
const emptyStream =
Symbol('emptyStream')
const stream = (value, next) => ({
value,
get next() { delete this.next; return this.next = next() }
})
const streamAdd = (s1, s2) =>
s1 === emptyStream || s2 === emptyStream
? emptyStream
: stream(s1.value + s2.value, _ => streamAdd(s1.next, s2.next))
const streamTake = (s = emptyStream, n = 0) =>
s === emptyStream || n <= 0
? emptyStream
: stream(s.value, _ => streamTake(s.next, n - 1))
function streamToArray(s = emptyStream) {
const r = []
while (s != emptyStream) {
r.push(s.value)
s = s.next
}
return r
}
const fibs =
stream(0, _ =>
stream(1, _ =>
streamAdd(fibs, fibs.next)))
console.log(String(streamToArray(streamTake(fibs, 20))))
0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181
I would do this like this (it's also a little bit faster because of caching):
function fibsRec(n) {
const cache = {
1: 1,
0: 1
}
rec(n)
return Object.values(cache)
function rec(n) {
if (cache[n]) return cache[n]
cache[n - 1] ??= rec(n - 1)
cache[n - 2] ??= rec(n - 2)
return cache[n - 1] + cache[n - 2]
}
}
console.log(fibsRec(8))
Of course the easy answer would be to make a wrapper function that loops and calls fibsRec(i) each time, but that's not what you're looking for.
First, you need to think about what fibsRec is doing to see why this isn't naturally as simple as it sounds. As you already know it gets the nth fibonacci number by finding the (n-1)th and (n-2)th and to get those, it keeps going further back.
But that means that to get the n-1 and n-2 numbers, you need to generate the sequence to n-1 and n-2, not only that, but when you start generating that sequence for, let's say n-1, and you have to calculate it's previous indices, then you need two more sequences, and so on and so on. It's extremely inefficient.
But the reason I'm bringing this up, is to say that we can't just create an empty array and have it push the number we'd return before returning it, because we're making so many sequences, our array is gonna contain all those results.
Look at this:
function fibArray(n) {
const output = [];
function fibsRec(n) {
if (n < 2) {
output.push(n)
return n;
}
let num = fibsRec(n - 2) + fibsRec(n - 1)
output.push(num);
return num;
}
fibsRec(n);
return output
}
console.log( fibArray(8) )
See how many times we're calculating a number on the fibonacci sequence?
We definitely can't directly use this approach. But what we can use is dynamic programming. What we'll do is, memoize (save) each fibonacci number we calculate to a dictionary, and the next time we're looking for it, instead of recursing a new sequence, we'll just get it from the dictionary directly.
That way, we're getting each fibonacci number only once. So when we calculate it, we can push it to our output array, and it'll be a clean fibonacci sequence.
function fibArray(n) {
const output = [];
const fibs = {}; // Create memo (a dictionary)
function fibsRec(n) {
if (fibs[n]) return fibs[n]; // Check memo
if (n < 2) {
fibs[n] = n;
output.push(n)
return n;
}
let num = fibsRec(n - 2) + fibsRec(n - 1) // Start with n-2 to eventually call fibsRec(0) before fibsRec(1) and push them in that order
fibs[n] = num; // Memoize
output.push(num);
return num;
}
fibsRec(n);
return output
}
console.log( fibArray(8) )

create a function that accepts an integer and generates an array containing pairs of integers [a, b] sorted by increasing values of a and then b

I've gotten stuck on this practice problem in my software engineering bootcamp, and am hoping that someone can point me in the right direction.
Write a function generatePairs that accepts an integer and generates an array containing the pairs of integers [a, b]. The pairs should be sorted by increasing values of a then increasing values of b.
here are some examples of what should be returned for different inputs:
generatePairs(3) // [ [0, 0], [0, 1], [0, 2], [0, 3], [1, 1], [1, 2], [1, 3], [2, 2], [2, 3], [3, 3] ]
generatePairs(2) // [ [0, 0], [0, 1], [0, 2], [1, 1], [1, 2], [2, 2] ]
generatePairs(1) // [ [0, 0], [0, 1], [1,1]]
generatePairs(0) // [ [0, 0]]
and here is my code so far:
function generatePairs (num){
array = [];
// 0 [0,0] [0,1]
// 1
// 2
for (i = 0; i<=num; i++){
array.push([i,i]);
if ((i+1)<=num) {
array.push([i,i+1])
}
if ( num - i <= num && i===0 && num < i ) {
array.push([i,num])
if (num + i < i) {
array.pop();
}
}
}
return array;
}
generatePairs(2) // [ [0, 0], [0, 1], [0, 2], [1, 1], [1, 2], [2, 2] ]
the issue I'm running into is that, for example, when I try it out with 2, I'm missing the [0,2] subarray. The methods I've tried to work around this have mostly consisted of additional if and else loops, but with each one I've tried I either end up with subarrays at the end that go higher than they should, or a semi-working system that would only work for 2 and not for any number that could be inputted into the function.
Isn't it much simpler than that?
function generatePairs(num) {
let arr = []
for (let i = 0; i <= num; i++) {
for (let j = i; j <= num; j++) {
arr.push([i, j])
}
}
return arr
}
console.log(generatePairs(2));
solution: (ninja code)
const generatePairs = n => Array.apply(null,{length:((n+1)*(n+2)/2)}).reduceRight((a,c,i)=>{
a.r.push([...a.p])
if(++a.p[1]>n) a.p[1]=++a.p[0]
return i?a:a.r
},{p:[0,0],r:[]})
for (let x=4;x--;) document.write(x,'->',JSON.stringify(generatePairs(x)), '<br>')
This is what you want right here. You loop through num for the first part until you get to num and for each first part loop from that first part to num.
function generatePairs(num) {
var output = []
for (var i = 0; i < num + 1; i++) {
for (var k = i; k < num + 1; k++) {
output.push([i, k])
}
}
return output
}
recursion
We can implement generatePairs in an wishful way -
const generatePairs = (n = 0) =>
chooseN(2, range(0, n))
range is a simple function that generates an array from a to b -
const range = (a = 0, b = 0) =>
a > b // base
? []
: [ a, ...range(a + 1, b) ] // inductive: a <= b
and chooseN is a generic that generates all n-sized samples from array a -
const chooseN = (n = 0, a = []) =>
n <= 0 // base
? [[]]
: a.length <= 0 // inductive: n > 0
? []
: chooseN(n - 1, a) // inductive: n > 0, non-empty a
.map(r => [a[0], ...r])
.concat(chooseN(n, a.slice(1)))
See generatePairs working in your own browser below -
const range = (a = 0, b = 0) =>
a > b
? []
: [ a, ...range(a + 1, b) ]
const chooseN = (n = 0, a = []) =>
n <= 0
? [[]]
: a.length <= 0
? []
: chooseN(n - 1, a)
.map(r => [a[0], ...r])
.concat(chooseN(n, a.slice(1)))
const generatePairs = (n = 0) =>
chooseN(2, range(0, n))
const log = x =>
console.log(JSON.stringify(x))
log(generatePairs(3))
// [[0,0],[0,1],[0,2],[0,3],[1,1],[1,2],[1,3],[2,2],[2,3],[3,3]]
log(generatePairs(2))
// [[0,0],[0,1],[0,2],[1,1],[1,2],[2,2]]
log(generatePairs(1))
// [[0,0],[0,1],[1,1]]
log(generatePairs(0))
// [[0,0]]
generators
Because combinatorial problems typically involve big solution spaces, it's common to generate combinations lazily. In JavaScript, we can do this using generators -
const chooseN = function* (n = 0, a = [])
{ if (n <= 0)
return yield []
if (a.length <= 0)
return
for (const r of chooseN(n - 1, a))
yield [a[0], ...r]
yield* chooseN(n, a.slice(1))
}
Notice the structurally similarity between this program and the one above -
const chooseN = function* (n = 0, a = [])
{ if (n <= 0) // if (n <= 0)
return yield [] // return [[]]
if (a.length <= 0) // else if (a.length <= 0)
return // return []
// else return:
for (const r of chooseN(n - 1, a)) // chooseN(n - 1, a).map(r =>
yield [a[0], ...r] // [a[0],...r])
yield* chooseN(n, a.slice(1)) // .concat(chooseN(n, a.slice(1)))
}
For example, we could write a solver that finds the first pair, [ a, b ] where a > 3 and 3*a is equal to 2*b. Critically, no pairs will be generated after the first solution is found -
const solver = (size = 0) =>
{ for(const [a, b] of generatePairs(size))
if (a > 3)
if (3 * a === 2 * b)
return [a, b]
}
console.log(solver(10))
// [ 4, 6 ]
And the solution a = 4, b = 6 is correct: 4 > 3 is true and 3*4 is equal to 2*6 (12).
Below, we can generate the entire array of pairs, if we wish, using Array.from -
const allPairs =
Array.from(generatePairs(3)) // <-- Array.from exhausts an iterable
console.log(allPairs)
// [[0,0],[0,1],[0,2],[0,3],[1,1],[1,2],[1,3],[2,2],[2,3],[3,3]]
Expand the snippet below to generate pairs using JavaScript's generators -
const range = (a = 0, b = 0) =>
a > b
? []
: [ a, ...range(a + 1, b) ]
const chooseN = function* (n = 0, a = [])
{ if (n <= 0)
return yield []
if (a.length <= 0)
return
for (const r of chooseN(n - 1, a))
yield [a[0], ...r]
yield* chooseN(n, a.slice(1))
}
const generatePairs = (n = 0) =>
Array.from(chooseN(2, range(0, n)))
const log = x =>
console.log(JSON.stringify(x))
log(generatePairs(3))
// [[0,0],[0,1],[0,2],[0,3],[1,1],[1,2],[1,3],[2,2],[2,3],[3,3]]
log(generatePairs(2))
// [[0,0],[0,1],[0,2],[1,1],[1,2],[2,2]]
log(generatePairs(1))
// [[0,0],[0,1],[1,1]]
log(generatePairs(0))
// [[0,0]]

Trying to Use Recursion to solve Fibonacci (javascript)

This is the question:
Given a positive integer num, return the sum of all odd Fibonacci numbers that are less than or equal to num.
The first two numbers in the Fibonacci sequence are 1 and 1. Every additional number in the sequence is the sum of the two previous numbers. The first six numbers of the Fibonacci sequence are 1, 1, 2, 3, 5 and 8.
For example, sumFibs(10) should return 10 because all odd Fibonacci numbers less than or equal to 10 are 1, 1, 3, and 5.
This is what I tried
function sumFibs(num, total = [1, 1], n = (total.length - 1 + total.length - 2)) {
if(n == num){
return total;
}
total.push(n);
sumFibs(num, n = (total.length - 1 + total.length - 2), total);
};
Question
Is it possible to use my method to make this work, if so how do I fix the syntax? If not, how would you solve the problem.
Many thanks!
continuation passing style
Continuation passing style effectively gives you programmatic return. Using a CPS function recursively can make program complexity evaporate into thin air -
const identity = x =>
x
const sumfib = (n = 0, then = identity) =>
n <= 0
? then(0, 1, 1) // base case
: sumfib // inductive: solve smaller subproblem
( n - 1
, (sum, fib, temp) =>
then(sum + fib, temp, fib + temp)
)
console.log
( sumfib(0) // 0 = 0
, sumfib(1) // 1 = 0 + 1
, sumfib(2) // 2 = 0 + 1 + 1
, sumfib(3) // 4 = 0 + 1 + 1 + 2
, sumfib(4) // 7 = 0 + 1 + 1 + 2 + 3
, sumfib(5) // 12 = 0 + 1 + 1 + 2 + 3 + 5
, sumfib(6) // 20 = 0 + 1 + 1 + 2 + 3 + 5 + 8
, sumfib(7) // 33 = 0 + 1 + 1 + 2 + 3 + 5 + 8 + 13
)
loop/recur
loop and recur give us the ability to write recursive programs like the one above, but will not encounter a stack overflow error -
const recur = (...values) =>
({ recur, values })
const loop = f =>
{ let r = f()
while (r && r.recur === recur)
r = f(...r.values)
return r
}
const sumfib = (n = 0) =>
loop // <-- loop with vars
( ( m = n
, sum = 0
, fib = 1
, temp = 1
) =>
m <= 0 // <-- exit condition
? sum // <-- base case
: recur // <-- recur with updated vars
( m - 1
, sum + fib
, temp
, temp + fib
)
)
console.log
( sumfib(0) // 0 = 0
, sumfib(1) // 1 = 0 + 1
, sumfib(2) // 2 = 0 + 1 + 1
, sumfib(3) // 4 = 0 + 1 + 1 + 2
, sumfib(4) // 7 = 0 + 1 + 1 + 2 + 3
, sumfib(5) // 12 = 0 + 1 + 1 + 2 + 3 + 5
, sumfib(6) // 20 = 0 + 1 + 1 + 2 + 3 + 5 + 8
, sumfib(7) // 33 = 0 + 1 + 1 + 2 + 3 + 5 + 8 + 13
)
streamz
so-called streams are interesting because they can possibly generate infinite values, but we don't have to compute them all at once. Again we can define our program in simple terms and let useful primitives do all of the hard work -
const fibs =
stream(0, _ =>
stream(1, _ =>
streamAdd(fibs, fibs.next)))
console.log(streamTake(fibs, 10))
// [ 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 ]
console.log(streamTake(streamSum(fibs), 10))
// [ 0, 1, 2, 4, 7, 12, 20, 33, 54, 88 ]
We just implement stream, streamAdd, streamSum, and streamTake -
const emptyStream =
Symbol('emptyStream')
const stream = (value, next) =>
( { value
, get next ()
{ delete this.next
return this.next = next()
}
}
)
const streamAdd = (s1, s2) =>
s1 === emptyStream || s2 === emptyStream
? emptyStream
: stream
( s1.value + s2.value
, _ => streamAdd(s1.next, s2.next)
)
const streamSum = (s, sum = 0) =>
s === emptyStream
? emptyStream
: stream
( sum + s.value
, _ => streamSum(s.next, sum + s.value)
)
const streamTake = (s = emptyStream, n = 0) =>
s === emptyStream || n <= 0
? []
: [ s.value, ...streamTake(s.next, n - 1) ]
Expand the snippet below to verify the results in your own browser -
const emptyStream =
Symbol('emptyStream')
const stream = (value, next) =>
( { value
, get next ()
{ delete this.next
return this.next = next()
}
}
)
const streamAdd = (s1, s2) =>
s1 === emptyStream || s2 === emptyStream
? emptyStream
: stream
( s1.value + s2.value
, _ => streamAdd(s1.next, s2.next)
)
const streamSum = (s, sum = 0) =>
s === emptyStream
? emptyStream
: stream
( sum + s.value
, _ => streamSum(s.next, sum + s.value)
)
const streamTake = (s = emptyStream, n = 0) =>
s === emptyStream || n <= 0
? []
: [ s.value, ...streamTake(s.next, n - 1) ]
const fibs =
stream(0, _ =>
stream(1, _ =>
streamAdd(fibs, fibs.next)))
console.log(streamTake(fibs, 10))
// [ 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 ]
console.log(streamTake(streamSum(fibs), 10))
// [ 0, 1, 2, 4, 7, 12, 20, 33, 54, 88 ]
Four things
(1) You don't return the result of the recursive call, therefore it does never get passed up to the caller:
sumFibs(4, [1, 1]) -> sumFibs(4, [1, 1, 2]) -> sumFibs(4, [1, 1, 2, 3])
<- [1, 1, 2, 3]
// v the return you do
// v the return you need too
(2) In the recursive call, the order of arguments is wrong.
(3) I guess instead of taking the arrays length minus 1, you want to access the property at that position in the total array.
(4) Why do you actually n as an argument? As it is only depending on total, it could also just be a variable:
function sumFibs(num, total = [1, 1]) {
const n = total[total.length - 1] + total[total.length - 2];
if(n > num){
return total;
}
total.push(n);
return sumFibs(num, total);
}
console.log(sumFibs(19));
This can be solved without an array accumulator; use n as a counter and curr and prev vars to store the data necessary to compute the Fibonacci series. Whenever we have an odd curr, add it to the running total and pass it up the call stack.
const sumOddFibs = (n, curr=1, prev=0) => {
if (curr < n) {
return sumOddFibs(n, curr + prev, curr) + (curr % 2 ? curr : 0);
}
return 0;
};
console.log(sumOddFibs(10));
As an aside, recursion is a pretty poor tool for just about anything that involves a sequential 0..n counter. Iteration makes more sense: less overhead, easier to understand and no risk of blowing the call stack. I'd also separate computation of the Fibonacci series (which is a good use case for a generator) from filtering oddness and summing so that each step is independent and can be reused:
const sum = arr => arr.reduce((a, e) => a + e);
const odds = arr => arr.filter(e => e % 2);
function *fibsBelow(n) {
for (let prev = 0, curr = 1; curr < n;) {
yield curr;
const tmp = curr;
curr += prev;
prev = tmp;
}
}
console.log(sum(odds([...fibsBelow(10)])));

How to totalize positive and negative numbers

Can anyone help me how to totalize/Collect positive and negative numbers in javascript? What metodes shud I use
Some useful methods could be filter and reduce assuming you are referring to an array of numbers that you want to totalize [sic] (I assume you mean sum):
const nums = [5, 3, -2, 0, 9, -8, 7]
const positiveNumsTotal = nums.filter(num => num > 0).reduce((a, b) => a + b, 0)
const negativeNumsTotal = nums.filter(num => num < 0).reduce((a, b) => a + b, 0)
const overallTotal = nums.reduce((a, b) => a + b, 0)
console.log(`nums array: ${JSON.stringify(nums)}`)
console.log(`Postive number total: ${positiveNumsTotal}`)
console.log(`Negative numbers total: ${negativeNumsTotal}`)
console.log(`Overall total: ${overallTotal}`)

using es6 functions for matrix calculation

I need to make some calculations on elements of a sample matrix, which they are on selective diagonals (here is make a sum on 2 separated diagonals). So i can do it with a for loop easily:
let matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]] ;
let sum1=0;
let sum2 = 0;
for (var i=0;i<matrix.length-1;i++) {
sum1+=matrix[i][i+1];
sum2+=matrix[i+1][i];
}
console.log(sum1,sum2) ;
The question is:
Is possible to do this with es6 functions like reduce, map, etc without for loop?
Yes, it's possible with the reduce() method:
const matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]];
const sum1 = matrix.reduce((acc, x, i) =>
acc + (i < matrix.length - 1
? x[i + 1]
: 0
)
, 0);
const sum2 = matrix.reduce((acc, x, i) =>
acc + (i != 0
? x[i - 1]
: 0
)
, 0);
console.log(sum1,sum2);
Note that both reduce() and map() were introduced in ES5, not ES6.
You can use reduce
var output = matrix.reduce( (a,c,i,ar) => (
a[0] += ar[i][i+1] || 0 , //sum1
a[1] += (ar[i+1] ? ar[i+1][i] : 0), //sum2
a ), //return the accumulator
[0,0]); //initial value
Output is an array of [sum1, sum2]
Demo
var matrix = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 16]
];
var output = matrix.reduce((a, c, i, ar) => (
a[0] += ar[i][i + 1] || 0, //sum1
a[1] += (ar[i + 1] ? ar[i + 1][i] : 0), //sum2
a), //return the accumulator
[0, 0]); //initial value
console.log(output);

Categories