break up buffer into size rxjs - javascript

I have an observable get data from stream each time at size 512 each next I have to break it up to 200 char at other observable and keep [12] char in other buffer to concatenate with next block, I solve it by using new subject and for loop, I believe there maybe a better, more pretty solution.
received Observable ----------------------------------------
1st next [512] -------> [112] [200] [200] -------> [200] [200]
2nd next [512][112] --> [24][200][200] [88+112] --> [200] [200]
3rd next [512][24] --> [136] [200] [76+124] .....
nth iteration [512][194] --> [106][200][200][106+94] --> [200][200][200]
n+1th [512][6].......
maxValueSize = 200
this._sreamRecord$.subscribe(
{
next: (val) => {
const bufferToSend: Buffer = Buffer.concat([completationBuffer, val])
for (let i = 0; i < bufferToSend.length; i += maxValueSize) {
if (bufferToSend.length - i > maxValueSize) {
bufferStreamer.next(bufferToSend.slice(i, i + maxValueSize))
} else {
completationBuffer = bufferToSend.slice(i, i + maxValueSize)
}
}
},
complete() {
if (completationBuffer.length) {
bufferStreamer.next(completationBuffer)
}
bufferStreamer.complete()
}
})

You may want to consider a solution along these lines
const splitInChunksWithRemainder = (remainder: Array<any>) => {
return (streamRecord: Array<any>) => {
const streamRecordWithRemainder = remainder.concat(streamRecord);
let chunks = _.chunk(streamRecordWithRemainder, maxValueSize);
const last = chunks[chunks.length - 1];
let newRemainder = [];
if (last.length != maxValueSize) {
newRemainder = chunks[chunks.length - 1];
chunks.length = chunks.length - 1;
}
return {chunks, newRemainder};
};
}
let f = splitInChunksWithRemainder([]);
this._sreamRecord$.pipe(
switchMap(s => {
const res = f(s);
f = splitInChunksWithRemainder(res.newRemainder);
return from(res.chunks);
})
)
.subscribe(console.log);
The idea is to split each streamRecord with lodash chunk function after having concatenated the previous remainder, i.e. the array left as tail from the split of the previous streamRecord.
This is done using the function splitInChunksWithRemainder, which is an higher level function, i.e. a function which returns a function, in this case after having set the remainder coming from the previous split.
UPDATE after comment
If you need to emit also the last newRemainder, than you can consider a slightly more complex solution such as the following
const splitInChunksWithRemainder = (remainder: Array<any>) => {
return (streamRecord: Array<any>) => {
const streamRecordWithRemainder = remainder.concat(streamRecord);
let chunks = _.chunk(streamRecordWithRemainder, maxValueSize);
const last = chunks[chunks.length - 1];
let newRemainder = [];
if (last.length != maxValueSize) {
newRemainder = chunks[chunks.length - 1];
chunks.length = chunks.length - 1;
}
return {chunks, newRemainder};
};
}
const pipeableChain = () => (source: Observable<any>) => {
let f = splitInChunksWithRemainder([]);
let lastRemainder: any[];
return source.pipe(
switchMap(s => {
const res = f(s);
lastRemainder = res.newRemainder;
f = splitInChunksWithRemainder(lastRemainder);
return from(res.chunks);
}),
concat(defer(() => of(lastRemainder)))
)
}
_streamRecord$.pipe(
pipeableChain()
)
.subscribe(console.log);
We have introduced the pipeableChain function. In this function we save the remainder which is returned by the execution of splitInChunksWithRemainder. Once the source Observable completes, we add a last notification via the concat operator.
As you see, we have also to use the defer operator to make sure we create the Observable only when the Observer subscribes, i.e. after the source Observable completes. Without defer the Observable passed to concat as parameter would be created when the source Observable is initially subscribed, i.e. when lastRemainder is still undefined.

Related

How to use multiple promises in recursion?

I am trying to solve the problem where the script enters a website, takes the first 10 links from it and then goes on those 10 links and then goes on to the next 10 links found on each of these 10 previous pages. Until the number of visited pages will be 1000.
This is what it looks like:
I was trying to get this by using for loop inside promise and recursion, this is my code:
const rp = require('request-promise');
const url = 'http://somewebsite.com/';
const websites = []
const promises = []
const getOnSite = (url, count = 0) => {
console.log(count, websites.length)
promises.push(new Promise((resolve, reject) => {
rp(url)
.then(async function (html) {
let links = html.match(/https?:\/\/(www\.)?[-a-zA-Z0-9#:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()#:%_\+.~#?&//=]*)/g)
if (links !== null) {
links = links.splice(0, 10)
}
websites.push({
url,
links,
emails: emails === null ? [] : emails
})
if (links !== null) {
for (let i = 0; i < links.length; i++) {
if (count < 3) {
resolve(getOnSite(links[i], count + 1))
} else {
resolve()
}
}
} else {
resolve()
}
}).catch(err => {
resolve()
})
}))
}
getOnSite(url)
I think you might want a recursive function that takes three arguments:
an array of urls to extract links from
an array of the accumulated links
a limit for when to stop crawling
You'd kick it off by calling it with just the root url, and await all of the returned promises:
const allLinks = await Promise.all(crawl([rootUrl]));
On the initial call the second and third arguments could assume default values:
async function crawl (urls, accumulated = [], limit = 1000) {
...
}
The function would fetch each url, extract its links, and recurse until it hit the limit. I haven't tested any of this, but I'm thinking something along these lines:
// limit the number of links per page to 10
const perPageLimit = 10;
async function crawl (urls, accumulated = [], limit = 1000) {
// if limit has been depleted or if we don't have any urls,
// return the accumulated result
if (limit === 0 || urls.length === 0) {
return accumulated;
}
// process this set of links
const links = await Promise.all(
urls
.splice(0, perPageLimit) // limit to 10
.map(url => fetchHtml(url) // fetch the url
.then(extractUrls)); // and extract its links
);
// then recurse
return crawl(
links, // newly extracted array of links from this call
[...accumulated, links], // pushed onto the accumulated list
limit - links.length // reduce the limit and recurse
);
}
async fetchHtml (url) {
//
}
const extractUrls = (html) => html.match( ... )

Saving count variable through recursion with only 1 argument

What's the best way to "save" the returned variable from the previous stack all the way to the first call using only one argument?
I know of 2 techniques to 'save' variables in recursion, but the test cases don't let me implement them that way.
Prompt: reverse a string using recursion.
Test cases:
should be invoked with one argument
should use recursion by calling itself
Attempt 1 (using helper function):
var reverse = function(string) {
var str = string.split('');
var reversed = [];
var helper = function(i) {
reversed.unshift(str[i]);
if (i < str.length) {
i++;
helper(i);
}
};
helper(0);
return reversed.join('');
}
Attempt 2 (without helper + using extra arguments)
var reverse = function(string, index, prev) {
var prev = prev || [];
index = index || 0;
if (index < string.length) {
prev.unshift(string[index]);
index++;
reverse(string, index, prev);
}
return prev.join('');
};
What would be the 3rd way of doing this?
Thanks!
Source: #9 from https://github.com/JS-Challenges/recursion-prompts/blob/master/src/recursion.js
You don't need to save anything. If you order the return correctly the call stack will unwind and create the reversed string for you:
var reverse = function(string) {
if (string.length == 0) return string // base case
return reverse(string.slice(1)) + string[0] // recur
};
console.log(reverse("hello"))
By returning the result of the recursion before the first character you wind and unwind the stack before the first call returns. You can then get result without maintaining any state other than the call stack.
I'd store the information to be used later in the function body only, without passing it down the call chain:
var reverse = function(string) {
const { length } = string;
return string[length - 1] + (
string.length === 1
? ''
: reverse(string.slice(0, length - 1))
);
};
var reverse = function(string) {
const { length } = string;
return string[length - 1] + (
string.length === 1
? ''
: reverse(string.slice(0, length - 1))
);
};
console.log(reverse('foo bar'));
Others have shown better ways to write your reverse recursively.
But as to the actual question you asked, modern JS allows for default arguments. I tend not to use them very much, but they are very useful in JS to allow you to write this sort of recursion without helper functions. Thus,
const reverse = (string, index = 0, prev = []) => {
if (index < string.length) {
prev .unshift (string [index])
reverse (string, index + 1, prev)
}
return prev .join ('')
}
console .log (
reverse ('abcde')
)
Again, other answers have better versions of reverse. But this should show you how you can have a function that takes only one public variable and yet still uses its extra arguments.
Here's another way you can do it using destructuing assignment and a technique called continuation-passing style -
const cont = x =>
k => k (x)
const Empty =
Symbol ()
const reverse = ([ s = Empty, ...more ]) =>
s === Empty
? cont ("")
: reverse
(more)
(rev => cont (rev + s))
reverse ("hello world") (console.log)
// dlrow olleh
But watch out for really big strings -
const bigString =
"abcdefghij" .repeat (1000)
reverse (bigString) (console.log)
// RangeError: Maximum call stack size exceeded
Here's another technique called a trampoline which allows to think about the problem recursively but have a program that is both fast and stack-safe. Have your cake and eat it, too -
const recur = (...values) =>
({ recur, values })
const loop = f =>
{ let r = f ()
while (r && r.recur === recur)
r = f (...r.values)
return r
}
const reverse = (s = "") =>
loop // begin loop ...
( ( r = "" // state variable, result
, i = 0 // state variable, index
) =>
i >= s.length // terminating condition
? r // return result
: recur // otherwise recur with ...
( s[i] + r // next result
, i + 1 // next index
)
)
const bigString =
"abcdefghij" .repeat (1000)
console .log (reverse (bigString))
// jihgfedcba...jihgfedcba

JavaScript: create function that accepts callback as input and returns function; Output depends on invoke count

The objective of my code is:
Write a function "once" that accepts a callback as input and returns a function. When the returned function is called the first time, it should call the callback and return that output. If it is called any additional times, instead of calling the callback again it will simply return the output value from the first time it was called.
I tried the code below:
const once = (inputFunc) => {
let invCount = 0;
let firstCallOutput;
return function (num) {
invCount ++;
if (invCount === 1){
firstCallOuput = inputFunc(num);
return inputFunc(num);
}
else {
return firstCallOuput;
}
}
}
const addByTwoOnce = once(function(num) {
return num + 2;
});
// UNCOMMENT THESE TO TEST YOUR WORK!
console.log(addByTwoOnce(5)); //should log 7
console.log(addByTwoOnce(10)); //should log 7
console.log(addByTwoOnce(9001)); //should log 7
My code console logs out the correct values (7) in all three situations. But it fails 2/3 test specs.
What am I doing wrong? How can I pass the two test specs?
Here's a simplified once function -
const once = (f, memo) => x =>
memo === undefined
? (memo = f(x), memo)
: memo
const addTwo = x =>
x + 2
const addTwoOnce =
once(addTwo)
console.log(addTwoOnce(5)) //should log 7
console.log(addTwoOnce(10)) //should log 7
console.log(addTwoOnce(9001)) //should log 7
If you want to safeguard the call site from being able to set the memo, you can make the memo a local variable instead of a parameter -
const once = f =>
{ let memo
return x =>
memo === undefined
? (memo = f(x), memo)
: memo
}
Or maybe you want to safeguard against the potential for the user-supplied function to return undefined. These are all choices you can make with minimal impact on the semantic structure of the code -
const once = f =>
{ let hasRun = false
let memo
return x =>
hasRun
? memo
: (hasRun = true, memo = f(x), memo)
}
Related: constant will return a constant value, regardless of its input -
const constant = x => _ =>
x
const always7 =
constant(7)
console.log(always7(5)) //should log 7
console.log(always7(10)) //should log 7
console.log(always7(9001)) //should log 7
Related: memoise will cache a value for each unique input, only recomputing f if the input has not been seen before -
const memoise = (f, memo = new Map) => x =>
memo.has(x)
? memo.get(x)
: (memo.set(x, f(x)), memo.get(x))
let fib = n =>
n < 2
? n
: fib (n - 1) + fib (n - 2)
console.time("original")
console.log(fib(40))
console.timeEnd("original")
// 1503.43 ms
fib = memoise(fib)
console.time("memoised")
console.log(fib(40))
console.timeEnd("memoised")
// 0.175 ms
Ok,
First we will create a once function that accepts a callback function.
Then we need to create a variable to check if this is the first time or not.
You can make a boolean variable or counter whatever you want. OK,
Then we make a variable result to grap the output of the callback with the initial value of 0
function once(func) {
let isOnce = true
let result = 0
}
OK, after that, let's create a function that will return the callback value if this is the first time, and if not, we will just return the output value from the first time, which we stored to the result
function once(func) {
let isOnce = true
let result = 0
function runOnce(num) {
if(isOnce) {
isOnce = false
result = func(num)
return result
} else {
return result
}
}
}
Finally, we will return the runOnce function.
function once(func) {
let isOnce = true
let result = 0
function runOnce(num) {
if(isOnce) {
isOnce = false
result = func(num)
return result
} else {
return result
}
}
return runOnce
}
Ok, now we need to create a callback function that takes the input and increments it by 2.
function addByTwo(input) {
return input + 2
}
So, time to check
const always7 = once(addByTwo);
console.log(always7(5))
console.log(always7(10))
console.log(always7(9001))
It always runs once and gets the same result every time.
the result is always be 7, click

I need to extract every nth char of a string in Javascript

Ive been reading everything online but its not exactly what I need
var x = 'a1b2c3d4e5'
I need something to get me to
using 1 the answer should be abcde
using 2 the answer should be 12345
using 3 the answer should be b3e
the idea behind it if using 1 it grabs 1 skips 1
the idea behind it if using 2 it grabs 2 skips 2
the idea behind it if using 3 it grabs 3 skips 3
I dont want to use a for loop as it is way to long especially when your x is longer than 300000 chars.
is there a regex I can use or a function that Im not aware of?
update
I'm trying to some how implement your answers but when I use 1 that's when I face the problem. I did mention trying to stay away from for-loops the reason is resources on the server. The more clients connect the slower everything becomes. So far array.filter seem a lot quicker.
As soon as I've found it I'll accept the answer.
As others point out, it's not like regular expressions are magic; there would still be an underlying looping mechanism. Don't worry though, when it comes to loops, 300,000 is nothing -
console.time('while')
let x = 0
while (x++ < 300000)
x += 1
console.timeEnd('while')
// while: 5.135 ms
console.log(x)
// 300000
Make a big string, who cares? 300,000 is nothing -
// 10 chars repeated 30,000 times
const s =
'abcdefghij'.repeat(30000)
console.time('while string')
let x = 0
let interval = 2
let values = []
while (x < s.length)
{ values.push(s[x])
x += interval
}
let result = values.join('')
console.timeEnd('while string')
// while string: 31.990ms
console.log(result)
console.log(result.length)
// acegiacegiacegiacegiacegiacegiacegiacegia...
// 150000
Or use an interval of 3 -
const s =
'abcdefghij'.repeat(30000)
console.time('while string')
let x = 0
let interval = 3
let values = []
while (x < s.length)
{ values.push(s[x])
x += interval
}
let result = values.join('')
console.timeEnd('while string')
// while string: 25.055ms
console.log(result)
console.log(result.length)
// adgjcfibehadgjcfibehadgjcfibehadgjcfibe...
// 100000
Using a larger interval obviously results in fewer loops, so the total execution time is lower. The resulting string is shorter too.
const s =
'abcdefghij'.repeat(30000)
console.time('while string')
let x = 0
let interval = 25 // big interval
let values = []
while (x < s.length)
{ values.push(s[x])
x += interval
}
let result = values.join('')
console.timeEnd('while string')
// while string: 6.130
console.log(result)
console.log(result.length)
// afafafafafafafafafafafafafafafafafafafafafafa...
// 12000
You can achieve functional style and stack-safe speed simultaneously -
const { loop, recur } = require('./lib')
const everyNth = (s, n) =>
loop
( (acc = '', x = 0) =>
x >= s.length
? acc
: recur(acc + s[x], x + n)
)
const s = 'abcdefghij'.repeat(30000)
console.time('loop/recur')
const result = everyNth(s, 2)
console.timeEnd('loop/recur')
// loop/recur: 31.615 ms
console.log(result)
console.log(result.length)
// acegiacegiacegiacegiacegiacegiacegia ...
// 150000
The two are easily implemented -
const recur = (...values) =>
({ recur, values })
const loop = f =>
{ let acc = f()
while (acc && acc.recur === recur)
acc = f(...acc.values)
return acc
}
// ...
module.exports =
{ loop, recur, ... }
And unlike the [...str].filter(...) solutions which will always iterate through every element, our custom loop is much more flexible and receives speed benefit when a higher interval n is used -
console.time('loop/recur')
const result = everyNth(s, 25)
console.timeEnd('loop/recur')
// loop/recur: 5.770ms
console.log(result)
console.log(result.length)
// afafafafafafafafafafafafafafa...
// 12000
const recur = (...values) =>
({ recur, values })
const loop = f =>
{ let acc = f()
while (acc && acc.recur === recur)
acc = f(...acc.values)
return acc
}
const everyNth = (s, n) =>
loop
( (acc = '', x = 0) =>
x >= s.length
? acc
: recur(acc + s[x], x + n)
)
const s = 'abcdefghij'.repeat(30000)
console.time('loop/recur')
const result = everyNth(s, 2)
console.timeEnd('loop/recur')
// loop/recur: 31.615 ms
console.log(result)
console.log(result.length)
// acegiacegiacegiacegiacegiacegiacegia ...
// 150000
Since I'm not an expert of regex, I'd use some fancy es6 functions to filter your chars.
var x = 'a1b2c3d4e5'
var n = 2;
var result = [...x].filter((char, index) => index % n == 0);
console.log(result);
Note that because 0 % 2 will also return 0, this will always return the first char. You can filter the first char by adding another simple check.
var result = [...x].filter((char, index) => index > 0 && index % n == 0);
As a variant:
function getNth(str, nth) {
return [...str].filter((_, i) => (i + 1) % nth === 0).join('');
}
console.log(getNth('a1b2c3d4e5', 2)); // 12345
console.log(getNth('a1b2c3d4e5', 3)); // b3e
What I'd suggest, to avoid having to iterate over the entire array, is to step straight into the known nth's.
Here's a couple of flavors:
function nthCharSubstr(str, nth) {
let res = "";
for (let i = nth - 1; i < str.length; i += nth) {
res += string[i];
}
return res;
}
More ES6-y:
const nthCharSubstr = (str, nth) =>
[...Array(parseInt(str.length / nth)).keys()] // find out the resulting number of characters and create and array with the exact length
.map(i => nth + i * nth - 1) // each item in the array now represents the resulting character's index
.reduce((res, i) => res + str[i], ""); // pull out each exact character and group them in a final string
This solution considers this comment as being valid.

Functional Programming: Calling a Curried Function

I'm implementing the game Tic Tac Toe/Naughts and Crosses in a functional programming style and have stumbled across a hurdle with curried functions.
I have a reoccurring pattern of functions in the form func(width, height, index) which I then wish to curry, binding width and height and leaving curriedFunc(index).
However the problem arises when I have functions that expect one of these curried functions to be defined at compile-time.
They cannot be defined at compile time, because they need input from the user to then bind the values to the function.
Below is some example code of the pattern I've encountered.
// Board indexes:
// 0 | 1 | 2
// ---+---+---
// 3 | 4 | 5
// ---+---+---
// 6 | 7 | 8
const getRowNumGivenWidth = w => i => Math.floor(i/w);
// I want to be able to declare nextIndexInRowGivenWidth() here, outside of main()
// but getRowNum() needs to be defined beforehand
const main = () => {
// User input:
const width = 3;
// ...
const getRowNum = getRowNumGivenWidth(width);
const nextIndexInRowGivenWidth = width => currentIndex => {
const rowNum = getRowNum(currentIndex);
const nextIndex = currentIndex + 1;
if (getRowNum(nextIndex) != rowNum)
result = nextIndex - width;
else
result = nextIndex;
return result;
};
const nextIndexInRow = nextIndexInRowGivenWidth(width);
const board = [0, 1, 2, 3, 4, 5, 6, 7, 8];
board.map(x => console.log(x, " -> ", nextIndexInRow(x)));
// ...
}
main();
The only way I can think of solving this is to pass the curried function as an argument (to nextIndexInRowGivenWidth() in this example).
However I don't think this is ideal as if a function requires a few similarly curried functions at run-time, it quickly becomes unwieldy to define and curry said function.
The ideal solution would be if I could somehow make the binding of the values dynamic, suppose I could put the declaration getRowNum = getRowNumGivenWidth(width); before main(). This way I could call something like getRowNum(someInt) to initialise getRowNum() which I could then use in other functions that are already expecting it to be defined.
As this is a reoccurring pattern in my code, I was wondering if there is a design pattern to achieve this.
I think you are looking for
const getRowNumGivenWidth = w => i => Math.floor(i/w);
const nextIndexInRowGivenWidth = width => {
const getRowNum = getRowNumGivenWidth(width);
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
return currentIndex => {
const nextIndex = currentIndex + 1;
if (getRowNum(nextIndex) != getRowNum(currentIndex))
return nextIndex - width;
else
return nextIndex;
};
};
const main = () => {
// User input:
const width = 3;
const nextIndexInRow = nextIndexInRowGivenWidth(width);
// ...
}
Alternatively, you could define that nextIndexInRowGiven… function not with the width as the first curried parameter, but with getRowNum itself as the parameter:
const getRowNumGivenWidth = w => i => Math.floor(i/w);
const nextIndexInRowGivenRowNumGetter = getRowNum => currentIndex => {
const nextIndex = currentIndex + 1;
if (getRowNum(nextIndex) != getRowNum(currentIndex))
return nextIndex - width;
else
return nextIndex;
};
const main = () => {
// User input:
const width = 3;
const nextIndexInRow = nextIndexInRowGivenRowNumGetter(getRowNumGivenWidth(width));
// ...
}

Categories

Resources