RxJava在给定时间范围内对相同类型的元素进行分组,同时保留顺序

时间:2017-07-13 07:36:45

标签: rx-java

我有一个热的observable,可以生成不同类型的事件,我想在给定的时间范围内连续发出相同类型的事件,如下所示:

输入:“A1”,“A2”,“A3”,“B1”,“B2”,“A4”,“A5”

输出 :(“A1”,“A2”),(“A3”),(“B1”,“B2”),(“A4”,“A5”)

在上面的例子中,事件“A3”来得太晚,因此没有与事件(“A1”,“A2”)分组。

我怎么能用RxJava做到这一点?

2 个答案:

答案 0 :(得分:0)

这可以按照以下方式完成

observable
  .scan(new ArrayList<T>(), groupingFunction)
  .lift(new DistinctUntilChanged<List<T>>())   

其中分组函数在类

之后扩展
public abstract class GroupingFunction<T> implements Func2<List<T>, T, List<T>> {

    @Override
    public List<T> call(List<T> group, T t) {
        if (group.isEmpty()) {
            group.add(t);
            return group;
        } 
        T first = group.get(0);
        if (isInSameGroup(first, t)) {
            group.add(t);
            return group;
        } else {
            List<T> result = new ArrayList<>();
            result.add(t);
            return result;
        }
    }

    protected abstract boolean isInSameGroup(T left, T right);
} 

此处isInSameGroup定义分组标准以及项目是否在同一时间范围内(也可以将源可观察源与Observable.interval合并以包括时间事件,然后可以对其进行反应以生成组)

DistinctUntilChanged实现如下

public class DistinctUntilChanged<T> implements Operator<T, T> {

    @Override
    public Subscriber<? super T> call(final Subscriber<? super T> child) {
        return new Subscriber<T>(child) {
            T previousHolder = null;

            @Override
            public void onNext(T cur) {
                T prev = previousHolder;
                previousHolder = cur;

                if (prev != null) {
                    if (prev == cur) {
                        request(1);
                    } else {
                        child.onNext(prev);
                    }
                } else {
                    request(1);
                }
            }

            @Override
            public void onError(Throwable e) {
                child.onError(e);
            }

            @Override
            public void onCompleted() {
                if (previousHolder != null) child.onNext(previousHolder);
                child.onCompleted();
                previousHolder = null;
            }
        };
    }
}

此实现类似于rx.internal.operators.OperatorDistinctUntilChanged,但使用简单的引用相等性并发出不同的最后一个对象,而不是第一个。

这应该产生连续项目所需的分组。

答案 1 :(得分:0)

感谢您的回答。

我花了一些时间来解决这个问题,最后找到了这个解决方案:

            // buffer the events that occur in a given timeframe
            observable.buffer(timespan, TimeUnit.MILLISECONDS)
            // transform each buffer of events into a list of buffers of events of the same type, while preserving the order of the events
            .map(buffer ->
                buffer.stream()
                    .collect(Collectors.groupingBy(
                                this::getKey,
                                LinkedHashMap::new,
                                Collectors.toList())
                    ).values()
            )
            // flatten the list of buffers into buffers
            .flatMapIterable(bufferList -> bufferList)
            .subscribe(buffer -> LOGGER.info(buffer));

但这对我来说仍然看起来有点过于复杂。还有其他解决方案吗?