patterncsharpMinor
pull things from lazy source till timeout is reached
Viewed 0 times
pullthingssourcetimeoutreachedlazyfromtill
Problem
I need to pull things from lazy source till timeout is reached in this fashion:
and I have this solution:
Am I just reinvented the wheel and it can be done using some external libs? like Rx/Ix maybe ...
var results = lazySource.SelectMany(item =>
{
//processing goes here
}).Pull(timeout: TimeSpan.FromSeconds(5), times: maxNumberOfIterations);and I have this solution:
public static class IEnumerableExtensions
{
public static IEnumerable Pull(this IEnumerable enumerable, int? times = null)
{
if (times == null)
return enumerable.ToArray();
else
return enumerable.Take(times.Value).ToArray();
}
public static IEnumerable Pull(this IEnumerable enumerable, TimeSpan timeout, int? times = null)
{
var stopwatch = new Stopwatch();
stopwatch.Start();
if (times != null) enumerable = enumerable.Take(times.Value);
using (var iterator = enumerable.GetEnumerator())
{
while (stopwatch.Elapsed < timeout && iterator.MoveNext())
yield return iterator.Current;
}
}
}Am I just reinvented the wheel and it can be done using some external libs? like Rx/Ix maybe ...
Solution
- A better name for
timeswould becount.
-
Your two
Pull methods are inconsistent:- The first one actually returns a copy of the entire input sequence (
ToArray()) while the second one doesn't.
- To keep it consistent with the standard LINQ methods the first method should also just enumerate the input sequence rather than making a copy.
The first method can then be rewritten as:
public static IEnumerable Pull(this IEnumerable enumerable, int? count = null)
{
return (times == null) ? enumerable : enumerable.Take(count.Value);
}Or if you prefer to create a new enumerator:
public static IEnumerable Pull(this IEnumerable enumerable, int? count = null)
{
var items = (times == null) ? enumerable : enumerable.Take(count);
foreach (var item in items)
{
yield return item;
}
}-
When i first read this question I assumed the intend was to only wait a maximum time for an item to arrive (i.e. input sequence is possibly blocking). Reading the code however seems that you just want to consume as many items as you can in a given time span (specifically it doesn't deal with blocking input sequences). Assuming the latter is what you wanted then I'd change the code to not use the enumerator interface but stick on a slightly higher level:
public static IEnumerable Pull(this IEnumerable enumerable, TimeSpan timeout, int? count = null)
{
var stopwatch = new Stopwatch();
stopwatch.Start();
var items = (times == null) ? enumerable : enumerable.Take(count.Value);
foreach (var item in items)
{
if (stopwatch.Elapsed >= timeout) { yield break; }
yield return item;
}
}Code Snippets
public static IEnumerable<T> Pull<T>(this IEnumerable<T> enumerable, int? count = null)
{
return (times == null) ? enumerable : enumerable.Take(count.Value);
}public static IEnumerable<T> Pull<T>(this IEnumerable<T> enumerable, int? count = null)
{
var items = (times == null) ? enumerable : enumerable.Take(count);
foreach (var item in items)
{
yield return item;
}
}public static IEnumerable<T> Pull<T>(this IEnumerable<T> enumerable, TimeSpan timeout, int? count = null)
{
var stopwatch = new Stopwatch();
stopwatch.Start();
var items = (times == null) ? enumerable : enumerable.Take(count.Value);
foreach (var item in items)
{
if (stopwatch.Elapsed >= timeout) { yield break; }
yield return item;
}
}Context
StackExchange Code Review Q#24492, answer score: 2
Revisions (0)
No revisions yet.