How to use sum operator of rxjs? - javascript

Things I have tried include following where values is array of values of which I want to find the sum.
I have also added necessary functions from rxjs as follows:
I get an error saying
typeError: Rx.Observable.from(...).sum is not a function
const { merge , interval ,from} = rxjs;
const { tap ,take ,sum } = rxjs.operators;
var sumSource = Rx.Observable.from(values).sum(function (x) {
return x;
});
var subscription = sumSource.subscribe(
function (x) {
console.log('Next: ' + x);
x.target.value = x;
},
function (err) {
console.log('Error: ' + err);
},
function () {
console.log('Completed');
}
);
Not much is available about sum on internet.Any inputs to fix and get the sum?

sum: regarding the official rxjs github repository they do not export/provide the sum operator anymore.
reduce operator reduce applies an accumulator function over the source Observable, and returns the accumulated result when the source completes.
scan operator scan applies an accumulator function over the source Observable and returns the accumulated result every emit.
setup
const values = [1,2,3,4,5];
const accumulator = (acc, curr) => acc + curr;
implement reduce
from(values).pipe(
reduce(accumulator, 0)
)
// Expected output: 15
implement scan
from(values).pipe(
scan(accumulator, 0)
)
// expected output: 1, 3, 6, 10, 15
I made a running stackblitz here.

Related

Add sum of all numbers in an array and print the final result

please don't kill me right away, because some topics are already here in the forum. I've read and tried a lot. I just don't get any further with my beginner knowledge.
My problem is the following: I have 4 arrays, the length of the arrays can have a different length each time. Now I would like to add the sum of all 4 arrays and get a final result.
I just can't really get any further than I want. Please bear with me and help me.
Here my example :
var MyData = '{"M":[{"M":{"MD":995,"PT":1,"TT":17,"D":0,"TID":44,"T":0,"HW":109,"KD":0,"TA":[4,17,77,17010,84,5,6,6,6,5,"xxxx",0,0,128,6,-1,0,34,[],0],"SD":1187,"OD":117,"SA":[1,65,67,194,187,7,8,7,6,6,"yyyy",0,0,-1,-1,-1,0,95,[],0]},"UM":{"PD":0,"TD":0,"L":{"ID":23,"ID":2,"VIS":14,"N":"bbbb","GD":102,"L":17,"W":1429,"D":113,"SPR":9,"Q":[[1647,1,2,5,-1,[[4,40,[114.0]],[5,46,[74.3]],[18,89,[43.6]],[116,34,[42.2]]],-1,-1,0,-1,-1,3,[1,5,3090,[7222,32,5,310,[[312,46,[11.4]],[311,55,[12.8]],[34,72,[19.7]],[30,28,[8.4]]],0]]],[187,2,2,5,-1,[[1,9,[82.4]],[2,86,[86.3]],[112,67,[28.1]],[19,35,[22.0]]],-1,-1,0,-1,-1,3,[2,6,2970,[7127,32,6,3240,[[311,28,[8.5]],[314,67,[18.7]],[32,83,[17.3]],[315,46,[8.0]]],0]]],[14650745,3,2,5,-1,[[3,97,[116.8]],[6,55,[74.8]],[109,42,[24.8]],[116,65,[67.0]]],-1,-1,0,-1,-1,3,[3,6,3590,[77381,32,6,3130,[[313,33,[6.3]],[310,83,[21.1]],[312,61,[13.8]],[311,36,[9.8]]],0]]],[14673,4,2,5,-1,[[7,82,[16.1]],[115,40,[21.0]],[121,87,[215,871.0]],[112,48,[22.4]]],-1,-1,0,-1,-1,3,[4,6,3570,[72077,32,2,2710,[[312,44,[11.0]],[311,52,[12.3]],[313,37,[6.8]],[38,38,[8.8]]],0]]],[14681483230,5,2,0,0,[[21,[5.0]]],1070,-1,0,630006,-1,2],[14649672824,6,2,15,-1,[[808,82,[47.1]],[811,77,[28.1]],[812,50,[20.0]],[815,35,[18.4]],[20018,100,[1.0]],[20016,7,[2060,12.0,2061,12.0,2062,12.0,2063,12.0,2064,12.0,2065,12.0,2066,12.0,2067,12.0,2068,12.0,148,12.0,2069,12.0,149,12.0,2070,12.0,150,12.0,151,12.0,2071,12.0,2072,12.0,2073,12.0,2074,12.0,2075,12.0,2076,12.0,2077,12.0,2078,12.0,2079,12.0,2020,12.0,2021,12.0,2022,12.0,2023,12.0,2024,12.0,2025,12.0,2026,12.0,2027,12.0,2028,12.0,2029,12.0,2030,12.0,2031,12.0,2032,12.0,2033,12.0,2034,12.0,2035,12.0,2036,12.0,2037,12.0,2038,12.0,2039,12.0]]],-1,-1,0,-1,-1,3,[65,6,3440,[]]]],"IDS":[[10021,1023],[10022,1033]],"SIS":[1033,1009,1040,100253],"AE":[[64,[8.0]],[503,[20.0]],[504,[48.0]],[504,[48.0]],[339,[50.0]],[504,[48.0]],[613,[50.0]],[66,[65.0]],[503,[65.0]],[503,[45.0]],[504,[30.0]],[504,[45.0]],[614,[8.0]],[66,[48.0]],[504,[60.0]],[66,[45.0]],[504,[48.0]],[614,[30.0]],[66,[24.0]]]}},"GA":{"L":[[287,30],[216,2224],[215,744],[298,60],[651,76],[650,90],[649,132],[240,50]],"M":[[287,30],[216,2720],[215,3808],[298,60],[651,48],[650,102],[649,125],[648,179],[240,50]],"R":[[287,30],[216,2968],[298,60],[651,76],[650,90],[649,132],[240,50]],"RW":[[215,2358],[216,433]]},"AST":[390,400],"ATT":0,"SM":0}],"O":[{"OID":8344,"DUM":false,"N":"xrr","E":{"BGT":0,"BGC1":14408394,"BGC2":1644825,"SPT":2,"S1":82,"SC1":144394,"S2":82,"SC2":163,"IS":1},"L":7,"LL":50,"H":3195,"AVZ":180,"CF":3911,"HF":16245,"PRE":13,"SUF":23,"TPX":-1,"MP":459,"R":0,"AID":48,"AR":0,"AN":"drum vv","aee":{"CF":237604,"BGT":7,"BGC1":16825,"BGC2":3012,"BGC3":864,"SPT":23,"S1":2,"SC1":30512,"S2":41,"SC2":164825,"S3":0,"SC3":164825},"RPT":0,"AP":[[0,1007,1062,76,1],[0,1170610,1067,757,4],[0,1211752,1056,755,4],[0,100,1059,72,4],[1,163,710,79,12],[2,16771,809,68,12],[3,2052697,772,504,12]],"VP":[],"SA":0,"VF":0,"PF":1,"RRD":0,"TI":-1},{"OD":1187,"DM":false,"N":"xyz","E":{"BGT":1,"BG1":81264,"BG2":5126,"SPT":1,"S1":82,"S1":16425,"S2":82,"S2":164825,"IS":1},"L":7,"LL":90,"H":6738,"AVP":87345,"CF":4591,"HF":5623,"PRE":13,"SUF":27,"TX":1,"P":8828,"R":0,"AD":88,"AR":7,"AN":"DDR ","aee":{"CF":1878,"BT":2,"BC1":14494,"BG2":1894,"BC3":-1,"SPT":0,"S1":-1,"S1":-1,"S2":-1,"SC2":-1,"S3":-1,"SC3":-1},"RPT":0,"AP":[[0,1417194,675,607,1],[0,2086,795,1180,4],[0,3363161,663,603,4],[0,7164676,769,1179,4],[1,489,490,318,12],[2,208,33,71,12],[3,4347,42,108,12],[4,112,818,61,12]],"VP":[],"A":0,"VF":0,"PF":1,"RD":0,"TI":-1,"RP":-1}]}'
var MyArray = JSON.parse(MyData)
MyArray.M[0].GA.L.forEach(element1 => console.log(element1[1]));
MyArray.M[0].GA.M.forEach(element2 => console.log(element2[1]));
MyArray.M[0].GA.R.forEach(element3 => console.log(element3[1]));
MyArray.M[0].GA.RW.forEach(element4 => console.log(element4[1]));
//So I give myself all the values ​​first.
//If I then use the for loop on one of the arrays, I get the output:
let sum = 0;
MyArray.M[0].GA.L.forEach(element1 => {
const MyArray = [element1[1]];
for (let i = 0; i < MyArray.length; i++) {
sum += MyArray[i];
}
console.log(sum);
})
//output: 30,2254,2998,3058,3134,3224,3356,3406
The number 3406 is the End Result, how can I print only the End result.
If there is another method to add all 4 arrays together at once, it would help me even more.
If possible an example for an array and an example for all 4 together please
you have to do three things: consolidate all the arrays, get the sum of all values, then print it
first, consolidate
const allArrs = [
...MyArray.M[0].GA.L,
...MyArray.M[0].GA.M,
...MyArray.M[0].GA.R,
...MyArray.M[0].GA.RW
]
then, the array method that would help the most here is Array.Reduce
const result = allArrs.reduce((accumulator, currentArray) => {
accumulator += currentArray[1]
return accumulator
}, 0)
then log the result!
As others have pointed out, this type of problem is very well suited for using a functional programming approach, where you simplify the problem by morphing it into a series of atomic operations that have no side-effects.
JavaScript does a great job of implementing the core functional programming methods of map(), filter(), and reduce(). For this problem, the only thing you need is reduce().
The code below could be made smaller and more efficient, but it was written to show each individual step.
const data = JSON.parse(rawData);
// subData is now an object whose members are the arrays you care about
const subData = data.M[0].GA;
// turn that into an array of arrays
const myArrays = Object.values(subData);
// now use reduce() to flatten the array of arrays into a single array with just
// the numbers you want to sum
const myNums = myArrays.reduce((acc, val) => acc.concat(val[1]), []);
// finally, reduce() again to sum the values
const sum = myNums.reduce((acc, val) => acc + val, 0);
console.log(sum);
You're on the right track. Simply move console.log(sum) outside of the final }) so it's not inside any loops.
I hope I understand what you are trying to do. You can simplify your code in this way.
function sum(arr) {
return arr.reduce((acc, item) => acc += item[1], 0);
}
const result = sum(MyArray.M[0].GA.L) + sum(MyArray.M[0].GA.M) + sum(MyArray.M[0].GA.R) + sum(MyArray.M[0].GA.RW);
This is a good example of a use for Array.prototype.reduce. The reduce method loops through all the elements of an array, and uses an accumulator to carry a result through the operation.
const someArray = [ /* any number of values */ ]
const sum = someArray.reduce( ( acc, val ) => ( acc + val )
You can take this a step further and write the callback as a function expression, and dump all of your arrays into a BIGGER array, and use reduce on THAT ONE too!
const summation = ( acc, val ) => ( acc + val )
const sumOfSums = ( acc, val ) => ( acc + val.reduce( summation, 0 ) )
const arrayOfArrays= [
MyArray.M[0].GA.L,
MyArray.M[0].GA.M,
MyArray.M[0].GA.R
MyArray.M[0].GA.RW
]
const total = arrayOfArrays.reduce( sumOfSums, 0 )
console.log( `output: ${total}` )

rxjs take until accumulated array length is size N

I have a simple data generator function like this. In summary, I have an array, and I am polling the data from the data generator, validating if the value can be added to the array, and then pushing the value to the array:
function* dataGeneratorFactory() {
while (true) {
for (const v of "abcdefghik") {
yield v;
}
}
}
const shouldExclude = (letter) => letter === "b" || letter === "e";
const items = [];
const maxItemsLength = 10;
const dataGenerator = dataGeneratorFactory();
while (items.length < maxItemsLength) {
const nextItem = dataGenerator.next();
if (shouldExclude(nextItem.value)) continue;
items.push(nextItem.value);
}
console.log(items);
My goal is to translate this logic into rxjs pattern. My only constraint is that the dataGeneratorFactory function is not modifiable. I came up with this:
// maxItemsLength, dataGenerator, and dataGeneratorFactory are
// from the code snippet above
import { from, map, mergeAll, range, takeWhile } from "rxjs";
const observeable = range(0, maxItemsLength).pipe(
map(() => from(dataGenerator).pipe(takeWhile(shouldExclude))),
mergeAll()
);
observeable.subscribe({
next: (e) => console.log(e),
});
However, I am not seeing anything by the console logger. What did I do wrong in this code?
The take operator should suffice:
import { filter, from, take, toArray } from "rxjs";
function* dataGeneratorFactory() {
while (true) {
for (const v of "abcdefghik") {
yield v;
}
}
}
const maxItemsLength = 10;
const shouldExclude = (letter) => letter !== "b" && letter !== "e";
from(dataGeneratorFactory())
.pipe(filter(shouldExclude), take(maxItemsLength), toArray())
.subscribe(console.log);
You may want to try something like this (the comments try to explain the logic).
// you start generating a stream of valued from the iterator using the from function
const observeable = from(dataGenerator).pipe(
// then take the first 10 elements of the stream and then complete upstream
take(10),
// filter out the values you do not want to keep
filter((v) => !shouldExclude(v))
);
// eventually you subscribe
observeable.subscribe({
next: (e) => console.log(e),
});
Here a stackblitz wit the full example.

how to obtain values from forEach javascript

I've always used array.forEach(element=>console.log(element) to see what I am obtaining from array; but now I want to obtain the values themselves.
Suppose I have the following code:
array=['1','2','3','4']
array.forEach(x=>x)//undefined
What I want to obtain is :
'1'
'2'
'3'
'4'
is this the correct approach or there is some other way I am not seeing right now?
array.forEach() presents each value to your callback one at a time. That's how it works and to use that, you put code into the callback that does something with the values.
As an example:
let array = [1,2,3,4];
let product = 1;
array.forEach(x => {
console.log(x);
// update the product variable
product *= x;
});
console.log(product);
If you're trying to do array.forEach(x, ...) in the console, then you see undefined because array.forEach() has no return value (and thus undefined).
Other array functions such a .map(), .filter(), .reduce(), etc... all have return values, and you can pick one of them depending upon what type of operation you're trying to do on the array.
For example, the previous code block, could have been written with .reduce()
let array = [1,2,3,4];
let product = array.reduce((total, x) => {
console.log(x);
return total * x;
}, 1);
console.log(product);
And, here's an example of .map() that returns a new array with every value squared:
let array = [1,2,3,4];
let product = array.map(x => {
return x ** 2;
}, 1);
console.log(product);

Implementing memoize pattern in JavaScript for multiple values

I'm trying to play a bit and implementing a memoization pattern for multiple values using JavaScript.
I managed to write the code for single value:
var lazy = {};
lazy.memoization = evaluator => {
const cache = new Map;
return key => {
cache.has(key) || cache.set(key, evaluator(key));
return cache.get(key);
};
};
var memoize = lazy.memoization(key => console.log('computing ', key));
memoize(1); // -> computing 1
memoize(2); // -> computing 2
Here is the version for multiple keys and it does not work as expected, it just outputs 'computing Array []', 'computing undefined':
var lazy = {};
lazy.memoization = evaluator => {
const cash = new Map;
return (...keys) => {
var values = [];
keys.reduce((v, f) => {
if (!cash.has(v)) {
cash.set(v, evaluator(v));
}
values.push(cash.get(v));
}, values);
return values;
};
};
var memoizeMultiple = lazy.memoization((...keys) => {
keys.forEach(key => console.log('computing ', key))
});
memoizeMultiple(1, 2);
What is wrong here?
There are a bunch of problems with your code. First off, reduce is a kind of fold, which means it usually is used to "collapse" a data structure into a single value. In order to do this, the function passed into reduce gets the accumulation value first and each value inside the data structure second.
const sumOf = ns => ns.reduce((sum, num) => sum + num, 0);
sumOf([1, 2, 3, 4, 5]); // -> 15
In this example, the data structure is an Array, which holds Number values. reduce is used to collapse all numbers in the array into a final value (by summing them up). The collapsing function is called a reducer function (it does addition in this example). Finally, the 0 passed into reduce is the seed value.
Let's track down what happens step by step:
In the first iteration, the reducer function is passed the seed value and the first number in the array. It therefor looks like:
(0, 1) => 0 + 1
The second iteration starts with the result from the first iteration as the accumulator value and the second number in the array:
(1, 2) => 1 + 2
So in complete, it works like this:
(0, 1) => 0 + 1
(1, 2) => 1 + 2
(3, 3) => 3 + 3
(6, 4) => 6 + 4
(10, 5) => 10 + 5
After the last iteration, reduce returns the final accumulator, which is 15 in this example.
OK, back to the code you provided. Your "multi arguments memoization" version uses reduce, but the reducer function doesn't return the intermediate results as a new accumulator value and you don't return the final result reduce produces.
Another problem is your evaluator function. The value it returns is stored inside the caching Map instance. In your code, it doesn't return anything other than undefined. Therefor, undefined is stored and returned on subsequent calls to the memoized function.
If we address these issues, it works:
var lazy = {};
lazy.memoization = evaluator => {
const cache = new Map();
return (...args) => {
return args.reduce((acc, arg) => {
if (!cache.has(arg)) {
cache.set(arg, evaluator(arg)); // stores the returned value inside the cache variable
}
return acc.concat(cache.get(arg));
}, []); // the result should be an array, so use that as the seed
};
};
var memoizeMultiple = lazy.memoization(value => {
console.log('computing ', value)
return value; // you have to return something in here, because the return value is stored
});
memoizeMultiple(1, 2);
I hope this clarifies things a bit. Happy coding!

Converting Array to Object using Reduce

Can someone explain how this is working.
Learning to use Array.reduce()
var votes = ['tacos','pizza','pizza','tacos','fries','ice cream','ice cream','pizza'];
var initialValue = {}
var reducer = function(tally, vote) {
if (!tally[vote]) {
tally[vote] = 1;
} else {
tally[vote] = tally[vote] + 1;
}
return tally;
}
var result = votes.reduce(reducer, initialValue)
The way how reduce works is pretty similar to map or filter. In this case, the reducer is responsible for reducing the array of objects into one object.
The reducer function iterates through all elements of your array. The function is called with two arguments, tally - result of reducing so far and vote - array element that is currently being processed.
If tally does not have a property named just like the element that is currently being processed/reduced, it adds such a key to the object and sets its value to one. Otherwise (key is present), it's incremented by one.
For more information go here
There's plenty of verbose explanations of reduce here and other places, but I think a simple visual demonstration might help
[1,2,3].reduce(function(a,b) { return a + b }, 0)
// (((0 + 1) + 2) + 3)
// => 6
You can see:
an input list of 3 elements results in 3 computations
the initial value is used in the computation with the first element
the result of one computation is used in the next computation …
… up until the last computation which is the result of reduce
Now as for your code, we're not building a sum of numbers, we're building up an Object that holds the tally count of each string in an array.
There's no point in me explaining what everyone else did, but it's not surprising this might've been confusing for you because no one explained that this is abuse of an Object.
In truth, an Object is actually not the best data structure choice for this reduction. Here, an Object is used to emulate the behaviour of a Map.
We'll set initialValue to a new Map() and you'll see how the reducer uses more descriptive syntax within. Note comments aren't even necessary because the code says everything it needs to.
var votes = ['tacos','pizza','pizza','tacos','fries','ice cream','ice cream','pizza']
var initialValue = new Map()
var reducer = function (tally, vote) {
if (tally.has(vote))
return tally.set(vote, tally.get(vote) + 1)
else
return tally.set(vote, 1)
}
var result = votes.reduce(reducer, initialValue)
console.log(Array.from(result.entries()))
Output
[
[ "tacos", 2 ],
[ "pizza", 3 ],
[ "fries", 1 ],
[ "ice cream", 2 ]
]
just for funs
I can show you that the visual representation of the sum via reduce is correct/accurate by writing a reducer that builds a string instead of actually adding the numbers
var initialValue = 0
var reducer = function(a,b) { return '(' + a + ' + ' + b + ')' }
var result = [1,2,3].reduce(reducer, initialValue)
console.log(result)
// (((0 + 1) + 2) + 3)
This technique might be useful for you when trying to understand/debug your own reducers
Basically Array.prototype.reduce() method applies a function against an accumulator and each value of the array to reduce it to a single value.
In your example the reduced value (the result of a count operation) is assigned as a property of an object called tally which is returned by .reduce();
I comment your with a brief explanation:
// your data in an array
var votes = ['tacos','pizza','pizza','tacos','fries','ice cream','ice cream','pizza'];
// optional value to use as the first argument to the first call of the callback when using Array.prototype.reduce().
var initialValue = {}
// tally = previousValue and vote = currentValue
var reducer = function(tally, vote) {
// if tally is not assign as a key in tally object, add key and add value of one, (basically count 1 for one element in your votes array)
if (!tally[vote]) {
tally[vote] = 1;
} else {
// otherwise if tally object has already this key, increment its value by one, (basically it counts how many times each item in votes array is present in the array)
tally[vote] = tally[vote] + 1;
}
return tally;
}
var result = votes.reduce(reducer, initialValue);
console.log(result);
Notes: you can actually avoid using of declaring a variable for initialValue and instead using only var result = votes.reduce(reducer, {});
API documentation:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
Some more examples and brief explanation:
https://www.airpair.com/javascript/javascript-array-reduce
I inserted some console.log messages in your code and this helped me understand what was going on.
var votes = ['tacos', 'pizza', 'pizza', 'tacos', 'fries', 'ice cream', 'ice cream', 'pizza'];
var initialValue = {}
var reducer = function(tally, vote) {
console.log("tally: ", tally);
console.log("vote: ", vote);
console.log("tally[vote]: ", tally[vote]);
if (!tally[vote]) {
tally[vote] = 1;
} else {
tally[vote] = tally[vote] + 1;
}
return tally;
}
var result = votes.reduce(reducer, initialValue)
console.log("result: " + JSON.stringify(result));
The reduce() method reduces the array to a single value.
The reduce() method executes a provided function for each value of the array (from left-to-right).
The return value of the function is stored in an accumulator (result/total).
You have this given list:
var votes = ['tacos','pizza','pizza','tacos','fries','ice cream','ice cream','pizza'];
Then you make an Initial List. You can modify this and the function will be applied for both lists.
var initialValue = {}
"reducer" is initialized as a function. The reason that we place the function in "reducer" is so we can call it more easily further on. You can do whatever you want in this function and it will be executed on the list in the upcoming steps
var reducer = function(tally, vote) {
if (!tally[vote]) {
tally[vote] = 1;
} else {
tally[vote] = tally[vote] + 1;
}
return tally;
}
Finally, the result of the function is stored into the variable.
var result = votes.reduce(reducer, initialValue)
Well, let's try to expand the iteration:
When you execute
votes.reduce(reducer, initialValue)
It actually does this:
reducer(initialValue, votes[0]); // step1, return {'tacos': 1}
reducer(returnedValueOfStep1, votes[1]); // step2, return {'tacos': 1, 'pizza': 1}
reducer(returnedValueOfStep2, votes[2]); // step3, return {'tacos': 1, 'pizza': 2}
reducer(returnedValueOfStep3, votes[3]); // step4 ...
reducer(returnedValueOfStep4, votes[4]); // step5 ...
reducer(returnedValueOfStep5, votes[5]); // step6 ...
reducer(returnedValueOfStep6, votes[6]); // step7 ...
reducer(returnedValueOfStep7, votes[7]); // step8 ...
I think it quite clear right now.
And usually, if we do not provide initialValue as the second parameter for reduce, it will take the first element of array as the initialValue, and starts iteration from the second one:
reducer(votes[0], votes[1]); // step1 ...
reducer(returnedValueOfStep1, votes[2]); // step2 ...
...

Categories