我对rxjs很新,并且阅读过十几个教程,但它仍然令人困惑。 让我们说我有一个用户ID列表,每3秒我想从REST服务查询每个用户的一些数据(在线游戏匹配信息)。多个用户可能玩过相同的匹配,因此getLastMatch()可能会为不同的用户返回相同的匹配ID。我想按匹配ID对结果流进行分组。 因此,对于用户1,我得到匹配ID 101,2> 100和3 - > 101。 我希望我的observable能够发出类似
的内容{
[
{"match": 101, "players": [1, 3]},
{"match": 100, "players": [2]},
]
}
这是我到目前为止提出的代码,但是我坚持使用最后一行 可观察到的与LT;可观察到的与LT; MatchData>>
class MatchData{
constructor(public matchId: number, public won: boolean) {}
}
const players = [1, 2, 3];
function getLastMatch(userId: number): Observable<MatchData> {
let data = new MatchData(100 + userId % 2, userId % 2 == 0);
return Observable.fromPromise(new Promise<MatchData>(resolve => resolve(data))));
}
const scheduler = Observable.interval(3000);
scheduler.map(Observable.from(players.map(p => getLastMatch(p))));
UPD:
这就是我最终的目标。
class MatchData {
constructor(public playerId: number, public matchId: number) {}
}
class GroupedMatchData {
constructor(public matchId: number, public playerIds: number[]) {}
}
const accounts = [1, 2, 3];
const scheduler = Observable.interval(3000);
function getMatch(id: number): Observable<MatchData> {
let promise = new Promise<MatchData>(resolve => resolve(new MatchData(id, 100 + id % 2)));
return Observable.fromPromise(promise);
}
function requestMatchData(): Observable<GroupedMatchData> {
return Observable.from(accounts.map(account => getMatch(account)))
.mergeAll()
.groupBy(match => match.matchId, match => match.playerId)
.flatMap(group => group.reduce((accumulator, current) => [...accumulator, current], [group.key]))
.map(array => new GroupedMatchData(array[0], array.slice(1)));
}
scheduler.take(1).flatMap(requestMatchData).subscribe(console.log);
对我的解决方案的任何评论都表示赞赏。
答案 0 :(得分:1)
我们可以使用Observable.forkJoin
将玩家列表映射到他们上次匹配的列表中。
使用flatMap
我们可以摆脱嵌套的Observables。
因为forkJoin
将以与玩家相同的顺序返回匹配,我们可以将每个(玩家,匹配)对合并为单个对象。
然后我们可以通过matchId对结果进行分组。
const scheduler = Observable.interval(3000);
scheduler
.flatMap(() => Observable.forkJoin(...players.map(id => getLastMatch(id))))
.map(mergeMatchesWithPlayers)
.map(groupPlayersByMatch)
.subscribe(console.log)
function mergeMatchesWithPlayers(matches: MatchData[]) {
return matches.map((match, i) => ({player: players[i], match}));
}
function groupPlayersByMatch(pairs: {player: number, match: MatchData}[]) {
const groups = [];
pairs.forEach(pair => {
const existingGroup = groups.find(group => group.match === pair.match.matchId);
existingGroup
? existingGroup.players.push(pair.player)
: groups.push({match: pair.match.matchId, players: [pair.player]})
});
return groups;
}