IlliakaillI
IlliakaillI

Reputation: 1558

Rx extension to keep generating events for N seconds?

What is the right Rx extension method (in .NET) to keep generating events for N seconds?

By 'keep generating events for N seconds' I mean that it will keep generating events in a loop since DateTime.Now till DateTime.Now + TimeSpan.FromSeconds(N)

I'm working on genetic algorithm that will generate number of hypotheses and propagate the most successful ones to the next generation. Need to constrain this guy in some elegant way.

Added later:

I've actually realized that I need to do pull instead of push and came-up with something like this:

public static class IEnumerableExtensions
{
    public static IEnumerable<T> Pull<T>(this IEnumerable<T> enumerable, int? times = null)
    {
        if (times == null) 
            return enumerable.ToArray();
        else
            return enumerable.Take(times.Value).ToArray();
    }

    public static IEnumerable<T> Pull<T>(this IEnumerable<T> enumerable, TimeSpan timeout, int? times = null)
    {
        var start = DateTime.Now;

        if (times != null) enumerable = enumerable.Take(times.Value);

        using (var iterator = enumerable.GetEnumerator())
        {
            while (DateTime.Now < start + timeout && iterator.MoveNext())
                yield return iterator.Current;
        }
    }
}

And usage would be:

var results = lazySource.SelectMany(item =>
{
    //processing goes here
}).Pull(timeout: TimeSpan.FromSeconds(5), times: numberOfIterations);

Upvotes: 0

Views: 326

Answers (2)

Lee Campbell
Lee Campbell

Reputation: 10783

Jon's post is pretty much spot on, however I noticed your edit where you suggested you would create your own extension methods to do this. I think it would be better* if you just used the built in operators.

//LinqPad sample
void Main()
{
    var interval = Observable.Interval(TimeSpan.FromMilliseconds(250));  
    var maxTime = Observable.Timer(TimeSpan.FromSeconds(10));
    IEnumerable<int> lazySource = Enumerable.Range(0, 100);

    lazySource.ToObservable()
            .Zip(interval, (val, tick)=>val)
            .TakeUntil(maxTime)
            .Dump();
}

*ie. easy for other devs to maintain and understand

Upvotes: 0

Jon Skeet
Jon Skeet

Reputation: 1500065

There may well be a cleaner way of doing this, but you could use:

// This will generate events repeatedly
var interval = Observable.Interval(...);

// This will generate one event in N seconds
var timer = Observable.Timer(TimeSpan.FromSeconds(N));

// This will combine the two, so that the interval stops when the timer
// fires
var joined = interval.TakeUntil(timer);

It's been a long time since I've done any Rx, so I apologise if this is incorrect - but it's worth a try...

Upvotes: 4

Related Questions