Предотвращение выбросов, если одна и та же эмиссия произошла x миллисекунд назад

Я хотел бы предотвратить возникновение эмиссии тогда и только тогда, когда один и тот же точный элемент был испущен за последние миллисекунды. Я посмотрел на дроссельные заслонки и операторы debounce, но я не уверен, могут ли они помочь мне здесь. Есть ли другой оператор, который я могу использовать, или я могу их каким-то образом создать?

Ответ 1

Вы можете сделать это с помощью groupByUntil, чтобы существенно разбить отдельные элементы

o
  .groupByUntil(x => x, x => x, x => Observable.timer(1000))
  .flatMap(grp => grp.first())

Ответ 2

Вы можете выполнить отметку времени и соединить каждый элемент, а затем проверить свои граничные условия времени и равенства.

   randomSource
                .timestamp()
                .pairwise()
                .where(pair => pair[0].timestamp - pair[1].timestamp < limit && pair[0].value === pair[1].value);

Затем примените .select(pair => pair[0].value), чтобы вернуть исходный элемент.

Рабочий пример в С# с источником, который генерирует случайные элементы между 1 и 5, расположенными в случайном порядке:

    static IObservable<T[]> Pairwise<T>(this IObservable<T> source)
    {
        source = source.Publish().RefCount();
        return source.Skip(1).Zip(source, (a, b) => new[] { a, b });
    }

    static void Main(string[] args)
    {

        var randomSource =
            Observable.Defer(() => Observable.Timer(TimeSpan.FromSeconds(new Random().NextDouble() * 2))).Repeat().Publish().RefCount().Select(_ => new Random().Next(1, 5));

        var limit = TimeSpan.FromSeconds(1);

        var sameDebounce =
        randomSource
            .Timestamp()
            .Pairwise()
            .Where(pair => pair[0].Timestamp - pair[1].Timestamp < limit && pair[0].Value == pair[1].Value);


        sameDebounce.Subscribe(c => Console.WriteLine("{0} {1}", c[0], c[1]));
        Console.ReadLine();

    }

Вывод:

[email protected]/7/2017 5:00:04 AM +00:00 [email protected]/7/2017 5:00:04 AM +00:00
[email protected]/7/2017 5:00:09 AM +00:00 [email protected]/7/2017 5:00:08 AM +00:00
[email protected]/7/2017 5:00:23 AM +00:00 [email protected]/7/2017 5:00:23 AM +00:00
[email protected]/7/2017 5:00:33 AM +00:00 [email protected]/7/2017 5:00:32 AM +00:00

Ответ 3

Как ваш вопрос не полностью объясняет сценарий, как сравнить следующее испущенное значение с последним испускаемым значением или любыми последними испускаемыми значениями или чем-то еще. Я бы взял общий путь для решения проблемы.

Пример: RxJava.

Вы можете использовать timestamp() с оператором filter() следующим образом:

ArrayList<String> list = new ArrayList<>();
        final long[] timeOfSubscribe = {-1};
        final long timeDuration = 2 * 1000; // 2 seconds
        Observable.fromIterable(list)
                .timestamp()
                .filter(item -> item.time() > (timeDuration + timeOfSubscribe[0]) && item.value().equals("your last value"))
                .doOnSubscribe(__ -> timeOfSubscribe[0] = Calendar.getInstance().getTimeInMillis())
                .subscribe();

Я предполагаю, что этот фрагмент может помочь вам просто изменить свой входной логический код сравнения значений, который находится в операторе filter(). Если вы ищете последнее испущенное значение, вы можете остановить последнее испущенное значение с помощью оператора doOnNext() (для простого случая), или если вы ищете все последние испускаемые значения, вам нужно сохранить испущенные значения в списке и проверить.

Надеюсь, это поможет.