【问题标题】:Implement a sliding window in RxJava2在 RxJava2 中实现滑动窗口
【发布时间】:2017-09-04 23:34:48
【问题描述】:

我正在尝试在 RxJava2 中实现一个简单的滑动窗口功能,但努力做我想做的事。

我的目标是获取对象流,即

["a", "b", "c", "d", "e"]

并应用一个滑动窗口,它将返回与每个元素相邻的元素。

即导致:

["a", "b"]
["a", "b", "c"]
["b", "c", "d"]
["c", "d", "e"]
["d", "e"].

I.E.

a----------------b----------------c----------------d----------------e
↓                ↓                ↓                ↓                ↓
↓                ↓                ↓                ↓                ↓
↓                ↓                ↓                ↓                ↓
↓                ↓                ↓                ↓                ↓
["a", "b"]       ["a", "b", "c"]  ["b", "c", "d"]  ["c", "d", "e"]  ["d", "e"]

我似乎无法弄清楚如何做到这一点。 Google Groups 的帖子似乎走在了正确的轨道上,但并没有完全得到我需要的结果: https://groups.google.com/forum/#!topic/rxjava/k-U5BijXinU

有什么想法吗?

【问题讨论】:

  • 我认为问题标题不适合问题陈述。滑动窗口类似于this,而您似乎想要每个元素的相邻元素。
  • 您的图表有问题。在项目实际作为输入到达之前,您不可能将其作为输出发出。例如。在收到“a”和“b”项后,您不能说下一个相邻项是“c”。否则buffer() 方法就可以了。
  • @jrook 我觉得和滑动窗口一样,但边界条件不同。
  • @YaroslavStavnichiy 可以为我的目的进行相位延迟,即缓冲是可以的。

标签: java rx-java rx-java2 reactivex


【解决方案1】:

也许正如@jrook 所说,这不是标准窗口的最佳选择。数组大小本身并不足以知道您在元素的哪一侧,所以我将其包装在一个简单的值类中。

这是我采用的解决方案。对于较大的流来说,这绝对不是一个好的解决方案,因为它会阻止首先读取整个 observable,这对于某些用例显然可能不太好(在我的情况下,没关系)。

 public static <R> ObservableTransformer<R, AdjacentPairing<R>> pairWithAdjacents() {
    return upstream -> upstream
        .toList()
        .flatMapObservable(list -> {
          ArrayList<AdjacentPairing<R>> pairings = new ArrayList<>(list.size());
          for (int i = 0; i < list.size(); i++) {
            pairings.add(AdjacentPairing.from(
                i == 0 ? null : list.get(i - 1),
                list.get(i),
                i == list.size() -1 ? null : list.get(i + 1)));
          }
          return Observable.fromIterable(pairings);
        });
  }

  @AutoValue
  public static abstract class AdjacentPairing<T> {
    @Nullable
    public abstract T getPrevious();
    public abstract T getElement();
    @Nullable
    public abstract T getNext();

    public static <T> AdjacentPairing<T> from(@Nullable T previous, T element, @Nullable T next){
      return new AutoValue_RxUtils_AdjacentPairing<>(previous, element, next);
    }
  }

【讨论】:

  • 看起来反应式编程让你的生活变得更加艰难。为什么你需要 RxJava 来完成这样的任务?
【解决方案2】:

根据您是否希望 observable 发出 List&lt;Item&gt;Observable&lt;Item&gt; 您可以使用 buffer()window() 运算符。解决方案不是那么干净,但非常简单:

Observable.fromArray("a", "b", "c", "d", "e")
        .startWith("")
        .buffer(3, 1)
        .map(strings -> {
            strings.remove("");
            return strings;
        })
        .filter(strings -> strings.size() > 1)

返回

["a", "b"]
["a", "b", "c"]
["b", "c", "d"]
["c", "d", "e"]
["d", "e"]

【讨论】:

  • 这本来是完美的,但是当使用更丰富的对象(即自定义类型)时,我无法弄清楚如何制作通用的哨兵元素(在这种情况下为“”)。就我而言,字符串实际上是例如客户事件。
  • 用 CustomerEvents 类中的一些值创建一个 CustomerEvents 实例并使其成为静态。然后,您可以通过访问静态成员来测试“哨兵”对象。
猜你喜欢
  • 2015-06-16
  • 2022-11-27
  • 2017-09-23
  • 2015-02-20
  • 2021-08-10
  • 1970-01-01
  • 1970-01-01
  • 2014-03-28
  • 2021-06-25
相关资源
最近更新 更多