How to use Observable.If without calling functions - rxjs5

Currently, functions isEven and isOdd are called for each IF. Is there a way that the functions are called only when the evaluation of the IF correspond to the logic path of the function?
Example: reference of JSBin: http://jsbin.com/wegesaweti/1/edit?html,js,output)
var isEven = function(x) {
console.log('function isEven called')
return Rx.Observable.return(x + ' is even');
};
var isOdd = function(x) {
console.log('function isOdd called')
return Rx.Observable.return(x + ' is odd');
};
var source = Rx.Observable.range(1,4)
.flatMap((x) => Rx.Observable.if(
function() { return x % 2; },
isOdd(x),
isEven(x)
));
var subscription = source.subscribe(
function (x) {
console.log('Next: ' + x);
});
Current output:
function isOdd called
function isEven called
Next: 1 is odd
function isOdd called
function isEven called
Next: 2 is even
function isOdd called
function isEven called
Next: 3 is odd
function isOdd called
function isEven called
Next: 4 is even
Expected output
function isOdd called
Next: 1 is odd
function isEven called
Next: 2 is even
function isOdd called
Next: 3 is odd
function isEven called
Next: 4 is even
Thank you!

Base on the RXJS docuemntation the thenSource and elseSource need to be Observable (or Scheduler for elseSource).
An alternative for your problem:
var source = Rx.Observable.range(1,4).flatMap((x) =>
(x % 2) == 1 ? isOdd(x) : isEven(x)
);
Working example: http://jsbin.com/godubemano/1/edit?html,js,output

Related

Polling using expand in rxjs gives an unexpected result

I am trying to setup a poller using expand but the behavior is not what I want
https://stackblitz.com/edit/rxjs-finalize-unsubscribe-6xy2yb?file=index.ts
checkExistence produces a random boolean - With the expand, I expect a recursive delayed call of the same checkExistence function producing random booleans every 5 seconds (after one initial call).
I also expect the stop to kick in 30seconds and stop the polling and 5 seconds later resume the random boolean stream. Any pointers will help.
Instead I get the same boolean value getting printed; also after the start is triggered, it produces batches of booleans together.
This isn't really a single question.
Assignment/function Invocation
A simplified example
The equals operator assigns a value to a variable. Function invocation returns a value
function inc(n){
return n + 1
}
const result = inc(5)
console.log(result); // 6
Here, the result holds the number value 6. Not a function that calculated 5 + 1. 5 + 1 only happens once here.
Now consider this function that randomly increments a number by either 1 or 2
function bump(n){
const nu = Math.random();
return nu < 0.5 ? n + 1 : n + 2
}
const result = bump(5);
console.log(result); // 7
console.log(result); // 7
console.log(result); // 7
console.log(result); // 7
console.log(result); // 7
Every time I print the result, it's the same. bump was only called once and only generated a random number once.
function bump(n){
const nu = Math.random();
return nu < 0.5 ? n + 1 : n + 2
}
console.log(bump(5)); // 7
console.log(bump(5)); // 7
console.log(bump(5)); // 6
console.log(bump(5)); // 7
console.log(bump(5)); // 6
Here, bump is called 5 times, and each time it generated a new random number.
Fixing checkExistence
There are two ways.
Instead of generating a value once and re-using it. Generate a new boolean in your poll every time you need one.
function checkExistencePoll(): Observable<boolean> {
const POLL = 5000;
return checkExistence().pipe(
expand(_ =>
timer(POLL).pipe(
switchMap(() => checkExistence()),
takeUntil(stop),
repeatWhen(() => start)
)
)
);
}
Have checkExistence return an observable that generates a new boolean on subscription
function checkExistence(): Observable<boolean> {
return defer(() => {
const nu = Math.random();
const rand = nu < 0.5;
console.log(nu, rand);
return of(rand);
});
}
Handling subscriptions
In your code, expand is generating an observable that subscribes to a subject ( called start) in order to decide when to repeat. Every observable expand creates does this. So each one repeats when start emits. You should expect batches of booleans equal to the number of concurrent observables you've created.

What does it mean to put a function into 'setState()' parameter in React-hook method?

First of all, please understand that I'm not good at English.
I am studying react-hook.
I am looking at an example code, and the factors(?) is declared in the function component as follows.
const lottoNumbers = useMemo(() => getWinNumbers(), []);
const [winNumbers, setWinNumbers] = useState(lottoNumbers);
const [winBalls, setWinBalls] = useState([]);
and setWinballs were used as follows.
for (let i = 0; i < winNumbers.length - 1; i++) {
timeouts.current[i] = setTimeout(() => {
setWinBalls((prevBalls) => [...prevBalls, winNumbers[i]]); <--------
}, (i + 1) * 1000);
What does 'setWinBalls((prevBalls) => [...prevBalls, winNumbers[i]])' mean here?
I didn't know that the 'set' function could have a function parameter.
The function setWinBalls() is using an arrow function which returns an object. Spread syntax has been used inside the arrow function which simply adds the current winNumber which is winNumbers[i] to the array and stores the updated array into another variable.
//example to understand what spread syntax does
var exampleArray = [1, 2, 3];
exampleArray = [...exampleArray, 4];
//exampleArray will be [1, 2, 3, 4]
Now let us try and understand what this arrow function is doing. The for loop can be written this way:
for (let i = 0; i < winNumbers.length - 1; i++) {
timeouts.current[i] = setTimeout(() => {
var updatedBalls = (prevBalls) => [...prevBalls, winNumbers[i]];
//winNumbers[i] will be added to the end to prevBalls array and updated array will be stored in updatedBalls
setWinBalls(updatedBalls);
}, (i + 1) * 1000);
Hope the code is clear to you now.

Create unique pair based on the giving array

I was unable to solve this question. Looking for the help of algo expert.
It will be great if the solution is provided in javascript, but it does not matter.
Given input:
[
[1,2,3]
[4,5,6]
[7,8]
...
]
Expected output:
[
[1,4,7]
[1,4,8]
[1,5,7]
[1,5,8]
[1,6,7]
[1,6,8]
[2,4,7]
[2,4,8]
[2,5,7]
[2,5,8]
[2,6,7]
[2,6,8]
[3,4,7]
[3,4,8]
[3,5,7]
[3,5,8]
[3,6,7]
[3,6,8]
]
You can use a recursive function. Here I have chosen to implement it as a generator, using * and yield. The caller can either iterate the function's result directly with a for loop, or turn it into an array:
function * generateCombis(data) {
if (data.length === 0) return yield [];
let [arr, ...rest] = data;
for (let val of arr) {
for (let combi of generateCombis(rest)) {
yield [val, ...combi];
}
}
}
let data = [
[1,2,3],
[4,5,6],
[7,8]
];
let result = Array.from(generateCombis(data));
console.log(result);

Test Dome pipeline for ruby

I'm practicing on test dome and come across to this question I don't have idea how to use lambda but I still try so I don't know if I'm right. Here's the instruction:
As part of a data processing pipeline, complete the implementation of the pipeline method:
The method should accept a variable number of functions, and it should return a new function that accepts one parameter arg.
The returned function should call the first function in the pipeline with the parameter arg, and call the second function with the result of the first function.
The returned function should continue calling each function in the pipeline in order, following the same pattern, and return the value from the last function.
For example, pipeline(-> (x) { x * 3 }, -> (x) { x + 1 }, -> (x) { x / 2 }) then calling the returned function with 3 should return 5.
And here's my code.
def pipeline(*funcs)
-> (arg) {
counter = 0
temp = 0
funcs.each do |func|
if counter == 0
temp += func.call(arg)
counter += 1
else
temp = func.call(temp)
end
end
return temp
}
end
fun = pipeline(-> (x) { x * 3 }, -> (x) { x + 1 }, -> (x) { x / 2 })
puts (fun.call(3))
Output:
Run OK
5
but I got this error.
done Example case: Correct answer
error Various functions: TypeError: pipeline.rb:7:in `+'
error Various data types: TypeError: pipeline.rb:7:in `+'
if you're curious here is the question its free.
https://www.testdome.com/d/ruby-interview-questions/6
Here's the starting code:
def pipeline(*funcs)
-> (arg) {
# write your code here
}
end
fun = pipeline(-> (x) { x * 3 }, -> (x) { x + 1 }, -> (x) { x / 2 })
puts (fun.call(3)) # should print 5
All you need is simply reduce the array of functions.
def pipeline(*args)
->(x) { args.reduce(x) { |acc, f| f.(acc) } }
end
fun = pipeline(-> (x) { x * 3 }, -> (x) { x + 1 }, -> (x) { x / 2 })
#⇒ #<Proc:0x0000561a73f48768#(pry):36 (lambda)>
fun.(3)
#⇒ 5
This is way simpler, by assigning a variable to control the flow of the operations make it crash
try this:
funcs.each do |func|
arg = func.call(arg)
end
return arg

Lua: How can I concatenate methods, as with the string methods?

The string funtions can used with this ways:
string.FUNCTION('myString', PARAMETER)
or replace 'string' with the string to use and call it as method
('myString'):METHOD(PARAMETER)
The last way is very fine to read and allows to concatenate methods.
-- example string operation
some_str, pos = ' some string', 1
-- default string syntax
while string.find(string.sub(some_str, pos, pos), '%s') do pos = pos +1 end
-- the same with syntactic sugar
while some_str:sub(pos, pos):find('%s') do pos = pos +1 end
So I tried to get the same behaviour with my own functions. But this fails.
The only way I found, was to use an additional parameter to say: return the object itself or the result.
Here a simple example for this.
calc = {
result = 0,
operator = '',
run = function(self, a, b, r) -- return self with r='s'
if b == 's' then r, b = b, nil end
if not b then b, a = a, self.result end
if self.operator == '+' then self.result = (a) + (b)
elseif self.operator == '-' then self.result = (a) - (b)
elseif self.operator == '*' then self.result = (a) * (b)
elseif self.operator == '/' then self.result = (a) / (b) end
if r ~= nil then return self else return self.result end
end,
add = function(self, a, b, r) self.operator = '+' return self:run(a, b, r) end,
sub = function(self, a, b, r) self.operator = '-' return self:run(a, b, r) end,
mul = function(self, a, b, r) self.operator = '*' return self:run(a, b, r) end,
div = function(self, a, b, r) self.operator = '/' return self:run(a, b, r) end
}
-- single operation
result = calc:add(12, 5)
-- concatenated operations
result = calc:add(12, 5, 's'):sub(3, 's'):mul(2, 's'):div(7)
Exists any way to do it same like in string operations?
Thanks in advance.
Your subsequent calls assign 's' to b parameter, not to r. Of course check for return self fails. Rather than give different behaviour to methods with some flags make them always return self instead and make a separate method to return current result - it will be much cleaner to read and program.
After that your call will look like:
result = calc:new(12):add(5):sub(3):mul(2):div(7):result()
Also, you don't really need proxy functions that go into one big function that splits into ifs anyway - just do everything inside add/sub/mul/div themselves.
You'll probably want more than one calc object as well, with each one having its own separate current result. Store common functions in a metatable and make :new create new instances with this metatable and separate entry for result.
local calc_meta = { __index = {
add = function(self, number) self._r = self._r + number return self end,
sub = function(self, number) self._r = self._r - number return self end,
mul = function(self, number) self._r = self._r * number return self end,
div = function(self, number) self._r = self._r / number return self end,
result = function(self) return self._r end
}}
local calc = {
new = function(self, number)
return setmetatable({
_r = number or 0
}, calc_meta) end
}
result = calc:new(12):add(5):sub(3):mul(2):div(7):result()
print(result)
-- 4
You can't completely duplicate Lua's behavior with strings - it is built-in into VM to treat string table as metatable for string values and cannot be programmed without modifying VM itself. You can get rid of extra result at end though if you add __add/__sub and other numeric methods to metatable so they would automatically "unwrap" your object to basic number value. Of course you won't be able to apply your methods to "unwrapped" value after that.

Resources