Given such observable
Rx.Observable.of([1,2,3,4,5])
which emits a single item (that is an array), what is the operator that will transform this observable to a one that emits 5 single items (or whatever the array consists of)?
The example is on .of, but it would be the same for fetching arrays via promises, there might be many other examples. Don't suggest to replace of with from
I can't think of an existing operator to do that, but you can make one up :
arrayEmitting$.concatMap(arrayValues => Rx.Observable.merge(arrayValues.map(Rx.Observable.of)))
or the simpler
arrayEmitting$.concatMap(Rx.Observable.of)
or the shortest
arrayEmitting$.concatMap(x => x)
That is untested so let me know if that worked for you, and that uses Rxjs v4 API (specially the last one). This basically :
process each incoming array of values as one unit (meaning that the next incoming array will not interlap with the previous one - that is why I use concatMap)
the incoming array is transformed into an array of observables, which are merged : this ensures the emission of values separately and in sequence
You can also use the flatMap operator (https://stackoverflow.com/a/32241743/3338239):
Observable.of([1, 2, 3, 4])
.flatMap(x => x)
.subscribe(x => console.log(x));
// output:
// 1
// 2
// 3
// 4
You can use from now to convert an array into a sequence.
https://www.learnrxjs.io/operators/creation/from.html
from([4,5,6])
mergeAll:
Observable.of([4, 5, 6])
.mergeAll()
.subscribe(console.log);
// output:
// 4
// 5
// 6
Dont understand why concatMap(x => x) or flatMap(x => x) works, it doesnt change anything.
This should work (rxjs 6 or above):
of([4,5,6]).pipe(mergeMap(from))
Related
In the following example, splice().splice() didn't work. What am I missing? How can I chain two splice methods in a single line? Thank you for any advice!
function test() {
var data = [0,1,2,3,4,5];
data.splice(0,2).splice(-1); // Removed only the first two elements, but not the last element.
console.log(data) // Returned [ 2, 3, 4, 5 ]
var data = [0,1,2,3,4,5];
data.splice(0,2); // Removed the first two elements.
data.splice(-1); // Removed the last element.
console.log(data) // Returned [ 2, 3, 4 ]
}
splice returns the removed elements, so chaining them in a single statement won't really work - you don't want to operate on the removed elements, you want to operate on the original array both times.
Usually, in this sort of situation, the right approach is to use slice instead, which is both easier to work with (just specify a start (inclusive) and end (exclusive) index) and is more functional (you get a new array instead of mutating an existing one - it's nice to avoid mutation when possible, makes code more understandable).
const data = [0,1,2,3,4,5];
console.log(data.slice(2,5));
You can do this, although I don't recommend this because it makes the code confusing
const data = [0,1,2,3,4,5];
console.log(data.splice(2,4).splice(0,3)); // Returned [2,3,4]
consider this code
example 1:
function plus(a) {return a+10}
([1]) // "110"
example 2:
var arr = [1,2,3,4,5,6,7]
arr[[1]] // 2
arr.splice([1],1);
arr // (6) [1, 3, 4, 5, 6, 7]
can someone explain why passing in an array as an argument, gets converted to a string? (that's what it looks like happened here)
can someone explain why passing in an array as an argument
It doesn't.
It gets treated as an array right up until the point where you try to use the addition operator on it.
It hits the step Let rprim be ? ToPrimitive(rval) and converts it according to those rules.
And so on until it calls the array's toString method.
Similar rules apply in the other examples.
In short: When it makes no sense at all to use an array in a given context, type conversion is applied to turn it into a data type that is apropriate.
Javascript automatically outputs a certain data type when two different data types are added.
Here are two examples:
2 + 3 // 5
2 + "hello" // "2hello"
When two numbers are added, an integer is output. However, 2 and hello can't be added numerically, so everything is first automatically converted to a string, and then appended.
The same thing happens in your case – a remains an array, but an array can't be added to a number. So both are converted to strings and then appended, and the end result is a string.
You were probablly thinking of adding a value to the end of an array. This is done using:
a.push(10);
Or, if you wanted to add the first item in the array and 10 to get the result 11, use:
return a[0] + 10
But you can't add a single number to a whole array, only to one of the items or at the end of the array.
Answer #1 - you get a string from the array.toString so you need to cast back to number - here I use +
function plus(a) {return +a+10}
console.log(plus([1]))
Second
var arr = [1,2,3,4,5,6,7]
console.log(arr[1]) // 2
console.log(arr[[1]]) // 2
arr.splice([1],1); // removes the second item
console.log(arr)
var arr = [1,2,3,4,5,6,7]
arr.splice(1,1); // just as if you had done this
console.log(arr) // [1, 3, 4, 5, 6, 7]
The + operator doesn't work for arrays. It only works for numbers or strings.
Since javascript can't use your array with the + operator, it converts it to string before. That's why plus([1]) is "110"
You can use the push method if you want to add to an array:
array.push(newElement);
In the second example, inside splice, your array is used with an operator that doesn't support it so it is converted to a number. If you look at the MDN definition of splice, you see it expects a number, not an array.
When you want to use splice, you don't pass an array as the first argument, you pass the index of the first element to remove. If you want to remove 2 from your array, you do arr.splice(1,1);
What is the data type of the elements outputted by spread? And is it possible to call only one element after spread, like with arrays?
Here is the example:
let ages = [1,2,3,1,4];
let chars = ['a','b','c'];
console.log(ages); // shows array> (5) [1, 2, 3, 1, 4]
console.log(...ages); // shows this> 1 2 3 1 4 - ??
console.log(typeof(ages[1]));// number
console.log(typeof(chars));// object
console.log(typeof(chars[1])); //string
//console.log(typeof(...ages)); - NOT WORKING
//console.log(typeof(...ages[1])); - NOT WORKING
Thanks!
What is the data type of the elements outputted by spread?
Each member of the array will have its own type.
And is it possible to call only one element after spread, like with arrays?
The point of a spread is to take all members of an array and spread them out.
If you want to access one member, then you shouldn't be using spread in the first place.
console.log(typeof(...ages))
This doesn't make sense. typeof tells you the type of something not many things.
Use a loop instead of a spread operator if you want to do something to each member of an array.
ages.forEach(member => { console.log(typeof member); });
console.log(typeof(...ages[1]));
Also doesn't make sense. ages[1] is the number 2. It isn't an iterable object. You can't spread it. If you want the type of that element then just:
console.log(typeof ages[1]);
This is my code in RxJs6:
const observable$ = interval(1000).pipe(
take(2),
map(x => interval(1500).pipe(
map(y => x+':'+y),
take(2),
concatAll()
)),
);
observable$.subscribe(obs => {
obs.subscribe(x => console.log(x));
});
I expect my code show the result like this:
0:0
1:0
0:1
1:1
But it actually shows:
why my code print data only one character every time ? And I think it should work like what i expected above not the actual result. anything wrong i understand about rxjs ?
This is because of concatAll(). It's typically used to flatten nested Observables but it can work with Promises and arrays (array-like objects) as well. Ant this is exactly what you're seeing here.
It thinks you want to flatten an array even when you have a string so it takes each item in the array (character in your case) and reemits it separately.
However, another question is what you wanted to achieve with concatAll.
I want to left join 2 Observables such that I always take the value from ObservableA, unless there is a corresponding value from ObservableB. In which case I want to use the value from ObservableB. The two Observables should join so will be a akin to a SQL left join.
From reading the RxJS Operators tree it does seem to me that Join would be the logical choice. I am unclear on how the join window works and how to ensure either observable could result in a join happening.
Can anyone provide a simple example?
You can do this easily with just merge where you put ObservableB first and then use take(1) to complete immediately. If ObservableB was empty then it'll emit the value from ObservableA.
const a$ = of(1);
const b$ = of('a');
merge(b$, a$)
.pipe(
take(1),
)
.subscribe(console.log);
Live demo: https://stackblitz.com/edit/rxjs6-demo-u5syjx?file=index.ts
There seems to be no out of the box operator for this. But you may want to zip first, then map the results with your custom logic to get what you want:
zip(observableA, observableB).map([a,b] =>{
if(idMatchesWithB) {return b}
else {return a}
}