Reputation: 2785
Having this:
Observable.combineLatest(localArray.map((i) => {
return <Observable that returns $value> }))
.map((statuses) => {
return statuses.filter((status) => {
return status.$value === CONDITION
});
}).subscribe((eligible: any[]) => {
...
Is it possible to map the results from the subscription back to the localArray
? I'd like to know which eligible
item belongs to which localArray
entry...
Thanks for the help.
I read somewhere that the order is preserved with combineLatest
. However, mapping directly to the index with a forEach
will not work since the eligible
results might return different length than the localArray
if the condition(s) are met.
I can always remove .map()
and do the filtering in the subscribe
block which will enable me to loop over the localArray
and update with the eligible
data directly as such: localArray.forEach((ai, i) => { ai.eligible = eligible[i] })
for example...
Upvotes: 2
Views: 3533
Reputation: 178
First, the code:
Observable
// Turn an array, promise, or iterable into an observable.
.from(localArray)
// Map values to inner observable, subscribe and emit in order.
.concatMap((arrayElement: any) => {
// Returning an observable that returns a value
return Observable.of(arrayElement);
})
// Emit only values that meet the provided condition.
.filter((value: any) => {
return value === 'Some condition';
})
// Reduces the values from source observable to a single value that's emitted when the source completes.
// If you need the current accumulated value on each emission, try scan - https://www.learnrxjs.io/operators/transformation/scan.html
// The second argument here is the seed, the initial value provided the first time reduce is called. (In this case, an empty array)
.reduce((filteredValue: any, accumulatedFilteredValues: any[]) =>{
accumulatedFilteredValues.push(filteredValue);
return accumulatedFilteredValues;
}, [])
.subscribe((filteredValueArray: any[]) => {
// Do something with the array of ordered, filtered values
});
First, I created an observable to emit each arrayElement in localArray
using from.
When each arrayElement
is emitted, I map that arrayElement
to an Observable that will return some value
(in this case I just return the arrayElement). I'm using concatMap because it will subscribe to the inner observable and emit their value once they complete, in the order they are emitted.
I use filter to only emit a value
that satisfies a condition. Filter takes a function that returns either true
or false
. If true
is returned, the value
will be emitted.
Finally, I use reduce to collect the filteredValue
and add it to an array of accumulatedFilteredValues
. Reduce takes a function as its first argument, and an optional seed as its second.
The function passed to reduce receives the most recent emission (filteredValue) as its first argument and an accumulated value as the second (the empty array [])
After applying these operators to the emitted values, the function passed to subscribe receives an array containing the filtered, ordered items from localArray
.
learn-rxjs is an excellent RxJS resource with examples and descriptions of various operators.
If you're using RxJS >= 5.5, consider using the pipeable operators instead. In that case, the code would look a little closer to this:
from(localArray).pipe(
concatMap((arrayElement: any) => {
return Observable.of(arrayElement);
}),
filter(value => {
return value === 'Some condition';
}),
reduce((filteredValue: any, accumulatedFilteredValues: any[]) => {
accumulatedFilteredValues.push(filteredValue);
return accumulatedFilteredValues;
}, [])
)
.subscribe((filteredValueArray: any[]) => {
// Do something with the array of ordered, filtered values
});
Upvotes: 1
Reputation: 19987
It is really hard to judge with the little amount of information that you have given whether that is a good idea or not, but it certainly doesn't sound like it to me. The reason I say that is because mapping back to the localArray
would create an implicit loop in your data stream. Perhaps that is exactly what you need, so that is up to you.
What you can do in this situation is simply also emit the index
(or some other identifier) that helps you map back to localArray
from the combineLatest
.
Something like this.
Observable.combineLatest(localArray.map((i) => {
return <Observable that returns $value> }))
.map((statuses) => {
return [i, statuses.filter((status) => {
return status.$value === CONDITION
})];
}).subscribe((eligible: [number, any[]]) => {
// eligible now is a tuple type where the left element is the index of the localArray
});
Upvotes: 1