【问题标题】:Merge subarrays using Observables使用 Observables 合并子数组
【发布时间】:2017-03-13 19:18:41
【问题描述】:

我有这个数据结构:

[{
    id : 1,
    name : "Item 1",
    subItems : [{
            id : 1,
            name : "SubItem 1"
        },{
            id : 2,
            name : "SubItem 2"
        }
    ]
}, {
    id : 2,
    name : "Item 2",
    subItems : [{
            id : 3,
            name : "SubItem 3"
        }, {
            id : 4,
            name : "SubItem 4"
        }
    ]
}]

我对 Web 服务进行以下调用以获取项目: this.dataService.get("items")

返回的是Observable<Item[]>。我可以使用哪些 Observable 运算符来仅获取子项的串联列表?我想得到这样的结果:

[{
    id : 1,
    name : "SubItem 1"
}, {
    id : 2,
    name : "SubItem 2"
},
{
    id : 3,
    name : "SubItem 3"
}, {
    id : 4,
    name : "SubItem 4"
}]

我应该使用flatMapconcat 之类的东西吗?

【问题讨论】:

  • 结果(完整结果)是数组吗?从你写的方式看不清楚
  • 你是否故意混合 subItems 和 searchProfiles?
  • ...源应该是一个数组吗?
  • @Meir 这是一种类型,应该是它们的子项。结果应该是一个数组,是的。
  • 是这样想的。见下面我的解决方案,你可以使用js数组函数来实现这个,而不需要进一步使用rxjs

标签: rxjs observable angular2-observables


【解决方案1】:

如果它是一个错字并且第二个元素也有subItems(而不是searchProfiles),你不需要 flatMap 或任何类似的东西,你可以使用 js 数组在普通地图中完成它运营商:

var transformed = [].concat(...result.map(item => item.subItems));

或者在你的情况下

httpResult$.map(result => [].concat(...result.map(item => item.subItems))

如果故意使用不同的键,您的内部映射将需要更多逻辑,但映射将完全相同

【讨论】:

    【解决方案2】:

    您想首先使用map() 运算符来仅提取您需要的字段,然后使用concatAll() 将对象数组展平(这是高阶 Observable 的一个小技巧,请参阅Subscribing to a nested Observable 了解更多信息):

    var data = [{
        id : 1,
        name : "Item 1",
        subItems : [
            { id : 1, name : "SubItem 1" },
            { id : 2, name : "SubItem 2" }
        ]
    }, {
        id : 2,
        name : "Item 2",
        searchProfiles : [
            { id : 3, name : "SubItem 3" },
            { id : 4, name : "SubItem 4" }
        ]
    }];
    
    Observable.from(data)
        .map(item => {
            if (item.searchProfiles) {
                return item.searchProfiles;
            } else if (item.subItems) {
                return item.subItems
            }
        })
        .concatAll()
        .subscribe(val => console.log(val));
    

    这会打印到控制台:

    { id: 1, name: 'SubItem 1' }
    { id: 2, name: 'SubItem 2' }
    { id: 3, name: 'SubItem 3' }
    { id: 4, name: 'SubItem 4' }
    

    或者,如果您真的希望输出为单个数组,则可以在 .concatAll().subscribe(...) 之间添加 toArray() 运算符,您将收到:

    [ { id: 1, name: 'SubItem 1' },
      { id: 2, name: 'SubItem 2' },
      { id: 3, name: 'SubItem 3' },
      { id: 4, name: 'SubItem 4' } ]
    

    【讨论】:

    • 让我烦恼的是,我在map 中获取了包含两个项目而不是每个项目的整个数组,就像在你的示例中一样。在您的情况下,我猜可观察对象分别发出每个项目?但我的情况是,整个数组被返回并发出一次,所以这就是我在map 中得到的
    • @Joel 那是因为我使用的是Observable.from(data)。如果您使用Observable.of(data),您将收到它作为一个大数组。
    • 好的。然后我将不得不做类似.map(items => { let subItems = []; items.forEach(item => subItems.push(item.subItems)); return subItems;) 的事情?不过语法可能有点偏离:)
    • @Joel 为什么需要这个?
    • 如果使用Observable.of(data) 我需要做类似的事情来获得我想要的结果。但是谢谢你,这对我有帮助。
    猜你喜欢
    • 2017-08-27
    • 1970-01-01
    • 1970-01-01
    • 2020-07-23
    • 2021-08-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多