我有两个对象流,即帐户和余额。
我需要根据id
和account_id
var accounts = Rx.Observable.from([
{ id: 1, name: 'account 1' },
{ id: 2, name: 'account 2' },
{ id: 3, name: 'account 3' },
]);
var balances = Rx.Observable.from([
{ account_id: 1, balance: 100 },
{ account_id: 2, balance: 200 },
{ account_id: 3, balance: 300 },
]);
预期结果:
var results = [
{ id: 1, name: 'account 1', balance: 100},
{ id: 2, name: 'account 2', balance: 200},
{ id: 3, name: 'account 3', balance: 300},
];
这对RxJs是否可行?
要清楚我知道如何使用普通的js / lodash或类似的东西来做这件事。在我的情况下,我从Angular Http模块获取这些流,所以我问我是否可以在这种情况下获得RxJs的好处
答案 0 :(得分:2)
根据您的一条评论,您的示例是模拟来自Angular Http调用的流。
所以而不是:
var accounts = Rx.Observable.from([
{ id: 1, name: 'account 1' },
{ id: 2, name: 'account 2' },
{ id: 3, name: 'account 3' },
]);
var balances = Rx.Observable.from([
{ account_id: 1, balance: 100 },
{ account_id: 2, balance: 200 },
{ account_id: 3, balance: 300 },
]);
我宁愿说它是:
var accounts = Rx.Observable.of([
{ id: 1, name: 'account 1' },
{ id: 2, name: 'account 2' },
{ id: 3, name: 'account 3' },
]);
var balances = Rx.Observable.of([
{ account_id: 1, balance: 100 },
{ account_id: 2, balance: 200 },
{ account_id: 3, balance: 300 },
]);
为什么: from
将逐个发出每个项目,of
将发出整个数组,我猜你的http响应就是整个数组。
那就是说,您可能希望实现的目标是:
const { Observable } = Rx;
// simulate HTTP requests
const accounts$ = Rx.Observable.of([
{ id: 1, name: 'account 1' },
{ id: 2, name: 'account 2' },
{ id: 3, name: 'account 3' }
]);
const balances$ = Rx.Observable.of([
{ account_id: 1, balance: 100 },
{ account_id: 2, balance: 200 },
{ account_id: 3, balance: 300 }
]);
// utils
const joinArrays = (accounts, balances) =>
accounts
.map(account => Object.assign({}, account, { balance: findBalanceByAccountId(balances, account.id).balance }));
const findBalanceByAccountId = (balances, id) =>
balances.find(balance => balance.account_id === id) || { balance: 0 };
const print = (obj) => JSON.stringify(obj, null, 2)
// use forkJoin to start both observables at the same time and not wait between every request
Observable
.forkJoin(accounts$, balances$)
.map(([accounts, balances]) => joinArrays(accounts, balances))
.do(rslt => console.log(print(rslt)))
.subscribe();
输出
[
{
"id": 1,
"name": "account 1",
"balance": 100
},
{
"id": 2,
"name": "account 2",
"balance": 200
},
{
"id": 3,
"name": "account 3",
"balance": 300
}
]
这是一个有效的普朗克:https://plnkr.co/edit/bc0YHrISu3FT45ftIFwz?p=preview
编辑1:
处理数组以构成结果可能不是最佳的性能,而不是返回一个数组,可能会尝试返回一个具有密钥的对象,即帐户的ID。这样您就可以删除findBalanceByAccountId
函数并使用更快的应用(此处仅修改代码):
const balances$ = Rx.Observable.of({
1: { account_id: 1, balance: 100 },
2: { account_id: 2, balance: 200 },
3: { account_id: 3, balance: 300 }
});
// utils
const joinArrays = (accounts, balances) =>
accounts
.map(account => Object.assign(
{},
account,
{ balance: balances[account.id].balance }
));
答案 1 :(得分:0)
如果您确实有2个可观察量以随机顺序发出Observable<{}>
的结果,则可以将它们组合起来。如果订单不是随机的,或者它们总是以“成对”的形式出现,则可以采用更有效的方式将它们组合起来。
import { from, merge } from 'rxjs';
import { map, scan, tap } from 'rxjs/operators';
const accounts = from([
{ id: 1, name: 'account 1' },
{ id: 2, name: 'account 2' },
{ id: 3, name: 'account 3' }
]);
const balances = from([
{ account_id: 1, balance: 100 },
{ account_id: 2, balance: 200 },
{ account_id: 3, balance: 300 }
]);
interface Outcome {
id: number;
name?: string;
balance?: number;
}
merge<Outcome>(
accounts,
balances.pipe(map(a => ({ id: a.account_id, balance: a.balance })))
)
.pipe(
scan<Outcome>((result: Outcome[], incomming) => {
const found = result.find(row => row.id === incomming.id);
if (found) {
Object.assign(found, incomming);
} else {
result.push(incomming);
}
return result;
}, []),
tap(r => console.log(r))
)
.subscribe();
请注意,结果是热烈观察。如果您只想发出单个结果并在所有结果都显示时完成,请将scan
运算符替换为reduce
运算符。
源代码基于RXjs版本6.您的导入版本可能与旧版本略有不同。