我有来自Firebase的可观察流的数据流。即
items: FirebaseListObservable<BucketlistItem[]> = [{
room: 'kitchen',
price: 200
}, {
room: 'kitchen',
price: 400
}, {
room: 'bedroom',
price: 400
}]
我想把它变成一个聚合列表,这样可以增加类似房间的价格。
[{
room: 'kitchen',
price: 600
}, {
room: 'bedroom',
price: 400
}]
通过订阅可观察的项目并在运行中聚合它以在条形图中显示它,我已经实现了这一点。但是,这似乎不是最佳解决方案,尤其是因为items数组经常在视图中更改。是否有一种聪明的方法可以使用observable来获得更强大的解决方案?
import {Component, Input, OnInit, Output, EventEmitter} from '@angular/core';
import {BucketlistItem} from "../../bucketlist/bucketlist-item";
import {FirebaseListObservable} from "angularfire2";
@Component({
selector: 'app-inspiration-header',
templateUrl: './inspiration-header.component.html',
styleUrls: ['./inspiration-header.component.css']
})
export class InspirationHeaderComponent implements OnInit, Input {
@Input() items: FirebaseListObservable<BucketlistItem[]>;
@Input() budget: string;
@Output() onBudget = new EventEmitter<string>();
public percentOfBudget: number;
public totalCost: number;
public barChartLabels: string[] = [];
public barChartData: any =
[{data: []}]
;
constructor() { }
ngOnInit() {
this.items
.subscribe(items => {
const aggregate = {};
let totalCost = 0;
for (const item of items) {
if (item.bucketed) {
totalCost += Number(item.price);
if (item.room in aggregate) {
aggregate[item.room] += Number(item.price);
} else {
aggregate[item.room] = Number(item.price);
}
}
}
this.setPercentageOfBudget(totalCost);
this.totalCost = totalCost;
for (const room in aggregate) {
this.barChartLabels.push(room);
this.barChartData[0].data.push(aggregate[room]);
}
this.barChartLabels = Object.keys(aggregate);
});
}
private setPercentageOfBudget(totalCost: number) {
this.percentOfBudget = Math.round(totalCost / Number(this.budget) * 100);
}
}
答案 0 :(得分:2)
根据您所描述的内容,您可能希望使用扫描运算符。
扫描操作符将在其源可观察值发出值时发出。但是,对扫描运算符的回调将同时接收源可观察量发出的当前值,以及过去提交的accumulated value
(概念与Array.reduce
的工作方式类似)。
这听起来很复杂,但实际上这意味着每次您的源可观察值发出一个值时,您的扫描操作符会将该新值与“旧值”组合,然后发出新的组合值。
你仍然需要编写逻辑来将新值与旧的累积值相结合,但我认为最终的observable会让你更接近你想要的。
// don't forget to import your operator
import 'rxjs/add/operator/scan';
.....
@Input() items: FirebaseListObservable<BucketlistItem[]>;
combinedItems: Observable<BucketlistItem[]>;
ngOnInit() {
this.combinedItems = items.scan((accumulated, current) => {
return this.combine(accumulated, current);
});
}
combine(total: BucketListItem[], newItem: BucketListItem[]) {
// implement your similar logic of combining
// [{room: 'kitchen', price: 200}] <-- accumulated
// with [{room: 'kitchen', price: 200}, {room: 'kitchen', price: 400}] <--- current
// to give your final output
}
无法实现组合逻辑(尽管您可以创造性地使用Array.reduce来简化代码)。