仍在确定正确使用不同的Rx *运营商并偶然发现以下问题:
我有以下类型的模型集合:
class Model {
final long timestamp;
final Object data;
public Model(long timestamp, Object data) {
this.timestamp = timestamp;
this.data = data;
}
}
此集合按升序排序(按时间戳排序)。
我的目标 - 按“序列”对它们进行分组。 “序列” - 是元素序列,其中每个元素都非常接近其邻居:
----A-B-C-----D-E-F---H-I--->
在这种情况下,我有3个“序列”。轴上的位置由模型的timestamp
属性(不是发射时间)定义。形成序列的最大距离应该是可配置的。
或者让我们采取更实际的例子:
List<Model> models = new ArrayList<Model>(10) {{
add(new Model(0, null));
add(new Model(5, null));
add(new Model(10, null));
add(new Model(100, null));
add(new Model(108, null));
add(new Model(111, null));
add(new Model(115, null));
add(new Model(200, null));
add(new Model(201, null));
add(new Model(202, null));
}};
在这种情况下,最大距离为10ms,我会得到3个序列 - (0,5,10),(100,108,111,115),(200,201,202)
此逻辑与debounce
运算符非常相似。但不是实时去抖,我需要通过一些自定义属性进行去抖动。
如果时间戳代表发射时间,我会这样做:
List<Model> models = new ArrayList<Model>(10) {{
add(new Model(0, null));
add(new Model(5, null));
add(new Model(10, null));
add(new Model(100, null));
add(new Model(108, null));
add(new Model(111, null));
add(new Model(115, null));
add(new Model(200, null));
add(new Model(201, null));
add(new Model(202, null));
}};
Observable<Model> modelsObservable = Observable.from(models).share();
modelsObservable.buffer(modelsObservable.debounce(10, TimeUnit.MILLISECONDS))
.subscribe(group -> {
//this is one of my groups
});
不一定需要进行辩护 - 我也在关注groupBy
运算符,但我无法找出正确的分组标准。
答案 0 :(得分:2)
我不会调度调度程序,但会利用缓冲区/窗口(取决于您是否需要下游可观察项或集合)和扫描。
在Rx.Net中,您可以通过以下方式实现:
var models = new[] { 0, 5, 10, 100, 108, 111, 115, 200, 201, 202 }
.ToObservable();
var enrichedModels = models.Scan(
new { Current = -1, Prev = -1 },
(acc, cur) => new { Current = cur, Prev = acc.Current })
.Skip(1).Publish();
enrichedModels.Buffer(() => enrichedModels.SkipWhile(em => em.Current < em.Prev + 10))
.Select(seq => seq.Select(em => em.Prev))
.Subscribe(seq =>
{
Console.WriteLine(String.Join(",", seq));
});
enrichedModels.Connect();
结果:
0,5,10
100,108,111,115
200,201
如果源可观察性很高,则可能会跳过发布/连接。 rx-java拥有相同的运算符,但不是匿名类型,我猜它们可以由元组或具体类替换。
答案 1 :(得分:1)
有点不同寻常,但您可以在这里使用TestScheduler
,按数据值安排值排放,然后使用此调度程序的去抖技巧并提前移动虚拟时间。
TestScheduler s = new TestScheduler();
Scheduler.Worker w = s.createWorker();
PublishSubject<Object> subject = PublishSubject.create();
for (Model m : model) {
w.schedule(() -> subject.onNext(m.data),
m.timestamp, TimeUnit.MILLISECONDS);
}
subject.buffer(subject.debounce(10, TimeUnit.MILLISECONDS, s))
.subscribe(list -> ...);
s.advanceTimeBy(Long.MAX_VALUE / 2, TimeUnit.MILLISECONDS);
w.unsubscribe();
(有人试图在RxJava中实现虚拟时间调度程序,但讨论被放弃了,建议的实现被拒绝了。)