【问题标题】:How to reduce an array of Int Publishers on Combine?如何减少组合上的 Int Publishers 数组?
【发布时间】:2020-07-11 00:19:59
【问题描述】:

我有一个 Int plublishers 数组正在通过网络进行更改,我想将它的总和分配给一个变量。 到目前为止,我想出了这个:

cancellable = Publishers.MergeMany(items.map { $0.$count } ).sink { value in
           print(value) 
        }

它正在打印所有的值,但我真正想要的是将它们全部减少为一个值,然后分配给其他地方。但是当我尝试做一个 reduce 时,就像这样:

   cancellable = Publishers.MergeMany(items.map { $0.$count } )
            .reduce(0){ counter, value in
                counter + value
            }.sink { value in
                print (value)
            }

它不再起作用了,该值永远不会被打印出来。我究竟做错了什么? 谢谢

编辑:

这似乎可行,但看起来效率不高

cancellable = Publishers.MergeMany(items.map { $0.$count })
      .sink { _ in
          let value = self.items.map { $0.count}.reduce(0) { counter, newValue in
              counter + newValue
          }
          print(value)
      }

【问题讨论】:

  • 你能解释一下你所说的“一系列 Int 出版商”是什么意思吗?在 最后一个值 到达之前,Combine reduce 不会运行。这些发布者在什么意义上发出最后一个值
  • 我注意到如果我在 reduce 中添加打印机,它会一直打印。在我的示例中,我只有 2 个发布者,两者的 $count = 1,所以总数应该是 2。但是如果我让应用程序运行,打印将永远进行,总是将最后一个值 + 新值添加到无穷大。似乎 reduce 不知道何时收集了所有发布者,但我不知道如何发出信号
  • @matt 看到我的评论。我认为这是问题所在,我不知道如何告诉reduce所有发布者都被“收集”了。在我上面的例子中,items 有 2 个对象:@Published private(set) var count = 0 我要做的是检查所有项目,将计数相加并得到结果。
  • @matt 它永远不会发出最后一个值,它会永远轮询。我只想要一个时间点上所有这些的总和。
  • 嗯,这就是你的答案。

标签: swift combine


【解决方案1】:

reduce 运算符将所有值减少到一个累加器中。它发出一次累加器作为其唯一输出,这仅在上游发布者完成时发生。

我怀疑您正在寻找的是 scan 运算符。它类似于reduce,但在每个事件中都会发出累加器。

【讨论】:

  • 我试过了,但它和reduce有同样的问题,它会永远添加值。它不会添加所有可用项目,例如 1+1,然后再次 1+1,而是永远添加 1+1,然后是 2+1、3+1。我希望“循环”在总结所有内容后重新开始。查看我编辑的代码,可以,但是效率低
  • @Wak 这是一个完全不同的问题,不是吗?
  • 是的。我想我没有提到我想要一个时间点的值的总和而不是连续的总和这一事实。我的错。
  • @Wak 不幸的是,除了实现自定义运算符之外,我没有想到什么可以解决您的第二个问题。我想不出可以实现这一目标的现有运营商的组合。
【解决方案2】:

最后一次编辑最后总结所有值实际上是最直接的方法,应该适用于大多数典型情况。

只有在考虑非常高的数字时才会效率低下,因为对于任何发布者的每个新值,您都在对所有发布者的值求和 - O(N) 时间操作。

所以,纯粹作为一种智力练习,为了提高效率,在 O(1) 时间内做到这一点的唯一方法是通过添加当前值和减去先前值来更新一些累积和同一出版商

let initialSum = items.reduce(0, { $0 + $1.count })

// publishers of tuples of: (current, previous)
let publishers = items.map { $0.$count.scan(($0.count, 0), { ($1, $0.0) }) }

let cancellable = Publishers.MergeMany(publishers)
                      // add current, subtract previous
                      .scan(initialSum, { $0 + $1.0 - $1.1 } )
                      // the first run will produce duplicates of initial sum
                      .removeDuplicates()
                      .sink{ print($0) }

【讨论】:

    猜你喜欢
    • 2021-07-14
    • 2011-10-13
    • 2019-06-18
    • 2016-05-05
    • 2023-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-25
    相关资源
    最近更新 更多