Получите предыдущий элемент в IObservable, не переоценивая последовательность

В IObservable последовательность (в Реактивных Расширениях для.NET), я хотел бы получить значение предыдущих и элементов тока так, чтобы я мог сравнить их. Я нашел пример онлайн подобным, ниже которого выполняет задачу:

sequence.Zip(sequence.Skip(1), (prev, cur) => new { Previous = prev, Current = cur })

Это хорошо работает за исключением того, что это оценивает последовательность дважды, которой я хотел бы избежать. Вы видите, что это оценивается дважды с этим кодом:

var debugSequence = sequence.Do(item => Debug.WriteLine("Retrieved an element from sequence"));
debugSequence.Zip(debugSequence.Skip(1), (prev, cur) => new { Previous = prev, Current = cur }).Subscribe();

Вывод показывает вдвое больше строк отладки, поскольку существуют элементы в последовательности.

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

13
задан dcstraw 12 May 2010 в 16:20
поделиться

3 ответа

Двойное вычисление является индикатором наблюдаемой холодной . Вы можете превратить его в Горячий, используя .Publish ():

var pub = sequence.Publish();
pub.Zip(pub.Skip(1), (...
pub.Connect();
3
ответ дан 1 December 2019 в 20:42
поделиться

Оказывается, вы можете использовать переменную для хранения предыдущего значения, обращения к нему и переназначения его в цепочке IObservable расширений. Это работает даже во вспомогательном методе. С помощью приведенного ниже кода я теперь могу вызвать CombineWithPrevious () в моем IObservable , чтобы получить ссылку на предыдущее значение без повторной оценки последовательности.

public class ItemWithPrevious<T>
{
    public T Previous;
    public T Current;
}

public static class MyExtensions
{
    public static IObservable<ItemWithPrevious<T>> CombineWithPrevious<T>(this IObservable<T> source)
    {
        var previous = default(T);

        return source
            .Select(t => new ItemWithPrevious<T> { Previous = previous, Current = t })
            .Do(items => previous = items.Current);
    }
}
-1
ответ дан 1 December 2019 в 20:42
поделиться

Если вам нужно получить доступ только к предыдущему элементу во время подписки, это, вероятно, самый простой способ, который сработает. (Я уверен, что есть способ лучше, может быть, оператор буфера в IObservable? Документация на данный момент довольно скудна, поэтому я не могу вам сказать.)

    EventArgs prev = null;

    sequence.Subscribe(curr => 
    {
        if (prev != null)
        {
            // Previous and current element available here
        }

        prev = curr;                              

    });

EventArgs - это просто замена типа аргумент вашего события.

0
ответ дан 1 December 2019 в 20:42
поделиться
Другие вопросы по тегам:

Похожие вопросы: