【问题标题】:Flatten observable array in Angular2在Angular2中展平可观察数组
【发布时间】:2017-04-16 13:00:36
【问题描述】:

我在我的 Angular2 应用程序中使用 Firebase 从我的数据库中检索数据。最简单的方法是在嵌套的 tags 列表中返回一组唯一值? IE。在我的示例中,我想返回 ["Sport", "Adventure", "Music"],其中省略了第二个 "Adventure"

{
"images": {
    "image1": {
        "path": "path",
        "date": 43534532123,
        "tags": {
           0: "Sport",
           1: "Adventure"
        }
    },
    "image2": {
        "path": "path",
        "date": 43534532123,
        "tags": {
           0: "Music",
           1: "Adventure"
        }
     }            

 }

我尝试了这种方法,但它似乎只从第一张图片中分割元素

 return this.af.database.list('/photos/user')
      .map(photos => photos.map(photo => photo.tags))
      .concatAll()
      .distinct()

但是,这种方法会产生正确的输出,但作为唯一标签的单独流而不是一个数组

 return this.af.database.list('/photos/user')
      .map(photos => photos.map(photo => photo.tags))
      .mergeAll()
      .mergeAll()
      .distinct()

【问题讨论】:

  • 我的错,应该是image1和image2
  • 老实说,你可能甚至不需要任何特殊的可观察魔法……你的 map 函数可以从 API 中获取对象并将其减少到该数组中。它的所有逻辑都可以放在map 回调中。 Observable 本身的操作符更适合操作数据流,而不是流中的数据。细微的差别,但很重要。这就是为什么我认为在map 的回调中可以简单地处理数据。您不需要distinct 排放,您需要更改实际数据。
  • 为了提高问题的质量,请澄清 observable this.af.database.list('/photos/user') 的结构。定义类型和成员。

标签: javascript angular firebase firebase-realtime-database observable


【解决方案1】:

更新

我在原始答案中假设它是包含单个项目的流。后来 OP 澄清它是 photos 列表的流。在这种情况下,我们使用Array#reduce 而不是Observable#reduce

return this.af.database.list('/photos/user')
  .map(photos => photos.map(photo => photo.tags)
      .reduce((allTags, current) => {
           return allTags.concat(
               current.filter(item => allTags.indexOf(item) === -1))
      }, []))

原始答案

distinct 在 observable 上返回流中唯一的单个值,但这不是我们在这里想要的运算符。可以生成一个包含所有标签的序列,每个标签都是一个单独的值,但是我们需要再次重新组合它们。

我们可以使用 reduce 代替,与 Array 对应项非常相似。它采用初始值 ([]) 并累加其他值。我们在每次迭代中建立了一个包含各个值的列表。在 reduce 之后,我们有一个独特的标签数组。

注意.list() 应该完成 observable 以使其工作。

return this.af.database.list('/photos/user')
      .map(photos => photos.map(photo => photo.tags))
      .reduce((allTags, current) => {
           return allTags.concat(
               current.filter(item => allTags.indexOf(item) === -1))
      }, [])

【讨论】:

  • 谢谢。这看起来是一个很好的解决方案,但不幸的是它不起作用。 1) 我收到一个错误,即 Property includes' 在类型 'any[] 上不存在。此外,当我订阅结果时,我没有得到任何输出。我应该如何确保 .list() 首先完成才能使其正常工作?
  • re: includes,它来自 ES2016,将 lib:["es2016"] 添加到 tsconfig.json。你可能需要一个 polyfill。我想我会改变答案以使用 indexOf()
  • 我明白了,对于 .list() 来说,我应该在调用 .map() 之前调用诸如 take(x) 之类的东西吗?
  • 看起来不太对劲。 map(photos => 收到什么对象?我希望/user 的数组。
  • 哼,那就是另外一回事了。从我的帖子中,从photo.tags)) 中删除一个),然后附加到[])。然后告诉我它是否有效。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-20
  • 2016-10-29
  • 2017-01-29
  • 2023-03-25
  • 1970-01-01
相关资源
最近更新 更多