【问题标题】:RXJava2 | Android: Filter arrayList and keep track of filterRXJava2 | Android:过滤arrayList并跟踪过滤器
【发布时间】:2017-10-27 21:18:30
【问题描述】:

场景:RXJava 2. Android。

假设你有一个来自 iterable 的 Observable,如下所示:Observable.fromIterable(arrayList<Something>),你需要用它做两件事:

  1. 过滤项目。

  2. 知道某个项目是否被过滤掉(又名:过滤器函数至少返回一次 false)。

这是一个类似的 observable(为了相关而极其简化):

    final ArrayList<Something> someArrayList = getTheArrayList();

    Observable
            .fromIterable(someArrayList)
            .subscribeOn(Schedulers.computation())
            .filter(new AppendOnlyLinkedArrayList.NonThrowingPredicate<Something>() {
                @Override
                public boolean test(final Something something) {
                    return something.isValid();
                }
            })
            .toList()
            .observeOn(AndroidSchedulers.mainThread())
            .doOnSuccess(new Consumer<List<Something>>() {
                @Override
                public void accept(@NonNull final List<Something> somethings) 
                    throws Exception {
                        // How can I tell if the filter above returned false
                        // at least once? 
                }
            })
            .subscribe();

要回答上述问题,一种选择是将原始someArrayListsomethings 进行比较。如果它们不同,那么,发生了一些事情。但这意味着列表必须以相同的顺序包含相同的项目,如果Something 是一个必须实现等号的复杂对象,这可能会成为问题。

我正在使用但我不喜欢的计划 B 是在可观察对象之外保留一个“布尔数组”,如下所示:

final boolean[] hasInvalidData = new boolean[1];

然后在.filter我可以做到:

    final isValid = something.isValid();
    if (!isValid) {
        hasInvalidData[0] = true;
    }
    return isValid;

如果成功,我可以这样做:

    if (hasInvalidData[0]) {
        // Something has been filtered
    }

问题是:有没有更好的方法?

更新

到目前为止,我所做的只是将originalList.size()finalEmitedList.size() 进行比较。如果它们不同,则意味着我的过滤器“过滤”了某些东西。

【问题讨论】:

    标签: android rx-java observable rx-java2


    【解决方案1】:

    按照我的阅读方式,这闻起来像 XY problem。如果您不需要跟踪元素并且只需要计算直到找到一个元素,那么一切都会变得容易得多:

     Observable
     .fromIterable(someArrayList)
     .subscribeOn(Schedulers.computation())
     .map(something -> something.isValid())
     .filter(bool -> bool)
     .first(false);
    

    如果你真的需要元素列表:

     Observable<Something> source = Observable
       .fromIterable(someArrayList)
       .subscribeOn(Schedulers.computation())
       .publish()
       .autoConnect(2);
    
    source
    .map(something -> something.isValid())
    .reduce(false, (a,b) -> a | b)
    .zipWith(source.toList(), (flag, list) -> {
       // do your stuff
    })
    .subscribe();
    

    【讨论】:

    • 这可能是一个 XY 问题(我意识到了这一点,感谢您刷新我的记忆),但是……我确实需要跟踪列表(最后,即在它之后过滤)。我只需要知道一个项目是否被过滤(任何)。我所做的基本上是,计算最后的项目数量并比较它们是否相同。由于唯一的操作是删除(过滤器),最终列表包含较少项目的唯一方法是过滤器返回 false。比布尔值好得多,但也许有更好的方法。
    • 也许您想将所有Somethings 转换为Pair&lt;Something, Boolean&gt;
    • 请注意,由于您没有 flatMap 或类似的东西,您将按顺序计算所有内容。
    • 我需要过滤后的列表,而不是过滤掉的项目,所以最终的列表总是&lt;=而不是原来的
    【解决方案2】:

    不确定它是否有效,但 Observable.sequenceEqual 是否有效:

    ArrayList<Object> list = ...
    Predicate myFilter = ...
    Observable<Object> observable = Observable.fromIterable(list);
    Observable.sequenceEqual(observable, observable.filter(myFilter))
        .subscribe(new Consumer<Boolean>() {
            @Override
            public void accept(@NonNull Boolean changed) throws Exception {
                // result here
            }
        });
    

    【讨论】:

      猜你喜欢
      • 2013-05-21
      • 2016-10-14
      • 2022-11-02
      • 1970-01-01
      • 1970-01-01
      • 2014-10-30
      • 2012-02-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多