Related
I want to translate the following code into a reactive flow (using System.Reactive in C#).
Method1, Method2 and Method3 are long running tasks. The result of Method2 is necessary in order to call Method3, but Method1 and Method2 can run in parallel. If result1 == null the whole operation can be terminated early with null.
Usually, Method2 returns faster than Method1, so Method3 could be started before Method1 finishes.
var result1 = Method1();
if (result1 == null) return null;
var result2 = Method2();
string result3 = null;
if (result2 != null)
{
result3 = Method3(result2);
}
var combinedResult = CreateResult(result1);
if (result2 != null)
{
combinedResult.Attr2 = result2;
}
if (result3 != null)
{
combinedResult.Attr3 = result3;
}
I am lost between nested functions and generics. The following code does not compile, because it has issues with generics and return types (especially the nested Select does not return a value but an Observable).
var observable1 = Observable.Start(() => Method1());
var observable2 = Observable.Start(() => Method2());
Observable.Zip(observable1, observable2, (result1, result2) =>
{
if (result2 != null)
{
var observable3 = Observable.Start(() => Method3(result2));
return observable3.Select(result3 =>
{
return SuperCombiner(result1, result2, result3);
};
}
return SuperCombiner(result1, null, null);
};
Here's what you need to get this to work:
var inner =
from m2 in Observable.Start(() => Method2())
from m3 in Observable.Start(() => Method3(m2))
select new { m2, m3 };
var query =
Observable
.Start(() => Method1())
.Publish(m1s =>
m1s
.Zip(
inner.TakeUntil(m1s.Where(m1 => m1 == null)),
(m1, m23) => new { m1, m23.m2, m23.m3 }))
.Where(x => x.m1 != null);
I have tested this using the following code:
public string Method1()
{
Console.WriteLine("Method1 Start");
Thread.Sleep(TimeSpan.FromSeconds(2.0));
Console.WriteLine("Method1 End");
return null; //"1";
}
public string Method2()
{
Console.WriteLine("Method2 Start");
Thread.Sleep(TimeSpan.FromSeconds(3.0));
Console.WriteLine("Method2 End");
return "2";
}
public string Method3(string x)
{
Console.WriteLine("Method3 Start");
Thread.Sleep(TimeSpan.FromSeconds(2.0));
Console.WriteLine("Method3 End");
return $"3-{x}";
}
The query only produces a value when Method1 returns a non-null value - otherwise it completes without producing a value.
Method3 is executed immediately after Method2 is complete unless Method1 has already returned null in which case Method3 is not executed.
This is computationally the most efficient implementation of what you asked for.
I've added some improvements to your draft and now it works as you described:
var stream1 = Observable.Start(Func1);
var stream2 = Observable.Start(Func2);
Observable.Zip(stream1, stream2, (res1, res2) =>
{
if (res1 == null)
return Observable.Start(() => new string[] { null });
if (res2 == null)
return Observable.Start(() => new string[] { res1, null });
return Observable.Start(() => Func3(res2)).Select(res3 => new[] { res1, res2, res3 });
})
.Merge()
.Subscribe(result =>
{
// 'result' is an array
// result[0] - result of Func1
// result[1] - result of Func2
// result[2] - result of Func3
// result.Length == 1 - means that Func1 returned 'null'
// result.Length == 2 - means that Func2 returned 'null'
});
But it's not a real 'Reactive' way because it contains imperative statements (like if operators for example).
If a method written in C# will be passed either a null or somewhere between 0 to 6,000,000 randomly generated and unsorted integers, what is the most efficient way to determine all modes and how many times they occurred? In particular, can anyone help me with a LINQ based solution, which I'm struggling with?
Here is what I have so far:
My closest LINQ solution so far only grabs the first mode it finds and does not specify the number of occurrences. It is also about 7 times as slow on my computer as my ugly, bulky implementation, which is hideous.
int mode = numbers.GroupBy(number => number).OrderByDescending(group => group.Count()).Select(k => k.Key).FirstOrDefault();
My manually coded method.
public class NumberCount
{
public int Value;
public int Occurrences;
public NumberCount(int value, int occurrences)
{
Value = value;
Occurrences = occurrences;
}
}
private static List<NumberCount> findMostCommon(List<int> integers)
{
if (integers == null)
return null;
else if (integers.Count < 1)
return new List<NumberCount>();
List<NumberCount> mostCommon = new List<NumberCount>();
integers.Sort();
mostCommon.Add(new NumberCount(integers[0], 1));
for (int i=1; i<integers.Count; i++)
{
if (mostCommon[mostCommon.Count - 1].Value != integers[i])
mostCommon.Add(new NumberCount(integers[i], 1));
else
mostCommon[mostCommon.Count - 1].Occurrences++;
}
List<NumberCount> answer = new List<NumberCount>();
answer.Add(mostCommon[0]);
for (int i=1; i<mostCommon.Count; i++)
{
if (mostCommon[i].Occurrences > answer[0].Occurrences)
{
if (answer.Count == 1)
{
answer[0] = mostCommon[i];
}
else
{
answer = new List<NumberCount>();
answer.Add(mostCommon[i]);
}
}
else if (mostCommon[i].Occurrences == answer[0].Occurrences)
{
answer.Add(mostCommon[i]);
}
}
return answer;
}
Basically, I'm trying to get an elegant, compact LINQ solution at least as fast as my ugly method. Thanks in advance for any suggestions.
I would personally use a ConcurrentDictionary that would update a counter and dictionary are faster to access. I use this method quite a lot and it's more readable.
// create a dictionary
var dictionary = new ConcurrentDictionary<int, int>();
// list of you integers
var numbers = new List<int>();
// parallel the iteration ( we can because concurrent dictionary is thread safe-ish
numbers.AsParallel().ForAll((number) =>
{
// add the key if it's not there with value of 1 and if it's there it use the lambda function to increment by 1
dictionary.AddOrUpdate(number, 1, (key, old) => old + 1);
});
Then it's only a matter of getting the most occurrence there is many ways. I don't fully understand your version but the single most is only a matter of 1 aggregate like so :
var topMostOccurence = dictionary.Aggregate((x, y) => { return x.Value > y.Value ? x : y; });
what you want: 2+ numbers could appear same times in an array, like: {1,1,1,2,2,2,3,3,3}
your current code is from here: Find the most occurring number in a List<int>
but it returns a number only, it's exactly a wrong result.
The problem of Linq is: loop cannot end if you don't want it continue.
But, here I result a list with LINQ as you required:
List<NumberCount> MaxOccurrences(List<int> integers)
{
return integers?.AsParallel()
.GroupBy(x => x)//group numbers, key is number, count is count
.Select(k => new NumberCount(k.Key, k.Count()))
.GroupBy(x => x.Occurrences)//group by Occurrences, key is Occurrences, value is result
.OrderByDescending(x => x.Key) //sort
.FirstOrDefault()? //the first one is result
.ToList();
}
Test details:
Array Size:30000
30000
MaxOccurrences only
MaxOccurrences1: 207
MaxOccurrences2: 38
=============
Full List
Original1: 28
Original2: 23
ConcurrentDictionary1: 32
ConcurrentDictionary2: 34
AsParallel1: 27
AsParallel2: 19
AsParallel3: 36
ArraySize: 3000000
3000000
MaxOccurrences only
MaxOccurrences1: 3009
MaxOccurrences2: 1962 //<==this is the best one in big loop.
=============
Full List
Original1: 3200
Original2: 3234
ConcurrentDictionary1: 3391
ConcurrentDictionary2: 2681
AsParallel1: 3776
AsParallel2: 2389
AsParallel3: 2155
Here is code:
class Program
{
static void Main(string[] args)
{
const int listSize = 3000000;
var rnd = new Random();
var randomList = Enumerable.Range(1, listSize).OrderBy(e => rnd.Next()).ToList();
// the code that you want to measure comes here
Console.WriteLine(randomList.Count);
Console.WriteLine("MaxOccurrences only");
Test(randomList, MaxOccurrences1);
Test(randomList, MaxOccurrences2);
Console.WriteLine("=============");
Console.WriteLine("Full List");
Test(randomList, Original1);
Test(randomList, Original2);
Test(randomList, AsParallel1);
Test(randomList, AsParallel2);
Test(randomList, AsParallel3);
Console.ReadLine();
}
private static void Test(List<int> data, Action<List<int>> method)
{
var watch = System.Diagnostics.Stopwatch.StartNew();
method(data);
watch.Stop();
Console.WriteLine($"{method.Method.Name}: {watch.ElapsedMilliseconds}");
}
private static void Original1(List<int> integers)
{
integers?.GroupBy(number => number)
.OrderByDescending(group => group.Count())
.Select(k => new NumberCount(k.Key, k.Count()))
.ToList();
}
private static void Original2(List<int> integers)
{
integers?.GroupBy(number => number)
.Select(k => new NumberCount(k.Key, k.Count()))
.OrderByDescending(x => x.Occurrences)
.ToList();
}
private static void AsParallel1(List<int> integers)
{
integers?.GroupBy(number => number)
.AsParallel() //each group will be count by a CPU unit
.Select(k => new NumberCount(k.Key, k.Count())) //Grap result, before sort
.OrderByDescending(x => x.Occurrences) //sort after result
.ToList();
}
private static void AsParallel2(List<int> integers)
{
integers?.AsParallel()
.GroupBy(number => number)
.Select(k => new
{
Key = k.Key,
Occurrences = k.Count()
}) //Grap result, before sort
.OrderByDescending(x => x.Occurrences) //sort after result
.ToList();
}
private static void AsParallel3(List<int> integers)
{
integers?.AsParallel()
.GroupBy(number => number)
.Select(k => new NumberCount(k.Key, k.Count())) //Grap result, before sort
.OrderByDescending(x => x.Occurrences) //sort after result
.ToList();
}
private static void MaxOccurrences1(List<int> integers)
{
integers?.AsParallel()
.GroupBy(number => number)
.GroupBy(x => x.Count())
.OrderByDescending(x => x.Key)
.FirstOrDefault()?
.ToList()
.Select(k => new NumberCount(k.Key, k.Count()))
.ToList();
}
private static void MaxOccurrences2(List<int> integers)
{
integers?.AsParallel()
.GroupBy(x => x)//group numbers, key is number, count is count
.Select(k => new NumberCount(k.Key, k.Count()))
.GroupBy(x => x.Occurrences)//group by Occurrences, key is Occurrences, value is result
.OrderByDescending(x => x.Key) //sort
.FirstOrDefault()? //the first one is result
.ToList();
}
private static void ConcurrentDictionary1(List<int> integers)
{
ConcurrentDictionary<int, int> result = new ConcurrentDictionary<int, int>();
integers?.ForEach(x => { result.AddOrUpdate(x, 1, (key, old) => old + 1); });
result.OrderByDescending(x => x.Value).ToList();
}
private static void ConcurrentDictionary2(List<int> integers)
{
ConcurrentDictionary<int, int> result = new ConcurrentDictionary<int, int>();
integers?.AsParallel().ForAll(x => { result.AddOrUpdate(x, 1, (key, old) => old + 1); });
result.OrderByDescending(x => x.Value).ToList();
}
}
public class NumberCount
{
public int Value;
public int Occurrences;
public NumberCount(int value, int occurrences)
{
Value = value;
Occurrences = occurrences;
}
}
Different code is more efficient for differing lengths, but as the length approaches 6 million, this approach seems fastest. In general, LINQ is not for improving the speed of code, but the understanding and maintainability, depending on how you feel about functional programming styles.
Your code is fairly fast, and beats the simple LINQ approaches using GroupBy. It gains a good advantage from using the fact that List.Sort is highly optimized, and my code uses that as well, but on a local copy of the list to avoid changing the source. My code is similar in approach to yours, but is designed around a single pass doing all the computation needed. It uses an extension method I re-optimized for this problem, called GroupByRuns, that returns an IEnumerable<IGrouping<T,T>>. It also is hand expanded rather than fall back on the generic GroupByRuns that takes extra arguments for key and result selection. Since .Net doesn't have an end user accessible IGrouping<,> implementation (!), I rolled my own that implements ICollection to optimize Count().
This code runs about 1.3x as fast as yours (after I slightly optimized yours by 5%).
First, the RunGrouping class to return a group of runs:
public class RunGrouping<T> : IGrouping<T, T>, ICollection<T> {
public T Key { get; }
int Count;
int ICollection<T>.Count => Count;
public bool IsReadOnly => true;
public RunGrouping(T key, int count) {
Key = key;
Count = count;
}
public IEnumerator<T> GetEnumerator() {
for (int j1 = 0; j1 < Count; ++j1)
yield return Key;
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public void Add(T item) => throw new NotImplementedException();
public void Clear() => throw new NotImplementedException();
public bool Contains(T item) => Count > 0 && EqualityComparer<T>.Default.Equals(Key, item);
public void CopyTo(T[] array, int arrayIndex) => throw new NotImplementedException();
public bool Remove(T item) => throw new NotImplementedException();
}
Second, the extension method on IEnumerable that groups the runs:
public static class IEnumerableExt {
public static IEnumerable<IGrouping<T, T>> GroupByRuns<T>(this IEnumerable<T> src) {
var cmp = EqualityComparer<T>.Default;
bool notAtEnd = true;
using (var e = src.GetEnumerator()) {
bool moveNext() {
return notAtEnd;
}
IGrouping<T, T> NextRun() {
var prev = e.Current;
var ct = 0;
while (notAtEnd && cmp.Equals(e.Current, prev)) {
++ct;
notAtEnd = e.MoveNext();
}
return new RunGrouping<T>(prev, ct);
}
notAtEnd = e.MoveNext();
while (notAtEnd)
yield return NextRun();
}
}
}
Finally, the extension method that finds the max count modes. Basically it goes through the runs and keeps a record of those int with the current longest run count.
public static class IEnumerableIntExt {
public static IEnumerable<KeyValuePair<int, int>> MostCommon(this IEnumerable<int> src) {
var mysrc = new List<int>(src);
mysrc.Sort();
var maxc = 0;
var maxmodes = new List<int>();
foreach (var g in mysrc.GroupByRuns()) {
var gc = g.Count();
if (gc > maxc) {
maxmodes.Clear();
maxmodes.Add(g.Key);
maxc = gc;
}
else if (gc == maxc)
maxmodes.Add(g.Key);
}
return maxmodes.Select(m => new KeyValuePair<int, int>(m, maxc));
}
}
Given an existing random list of integers rl, you can get the answer with:
var ans = rl.MostCommon();
I tested with the code below on my Intel i7-8700K and achieved the following results:
Lambda: found 78 in 134 ms.
Manual: found 78 in 368 ms.
Dictionary: found 78 in 195 ms.
static IEnumerable<int> GenerateNumbers(int amount)
{
Random r = new Random();
for (int i = 0; i < amount; i++)
yield return r.Next(100);
}
static void Main(string[] args)
{
var numbers = GenerateNumbers(6_000_000).ToList();
Stopwatch sw = Stopwatch.StartNew();
int mode = numbers.GroupBy(number => number).OrderByDescending(group => group.Count()).Select(k =>
{
int count = k.Count();
return new { Mode = k.Key, Count = count };
}).FirstOrDefault().Mode;
sw.Stop();
Console.WriteLine($"Lambda: found {mode} in {sw.ElapsedMilliseconds} ms.");
sw = Stopwatch.StartNew();
mode = findMostCommon(numbers)[0].Value;
sw.Stop();
Console.WriteLine($"Manual: found {mode} in {sw.ElapsedMilliseconds} ms.");
// create a dictionary
var dictionary = new ConcurrentDictionary<int, int>();
sw = Stopwatch.StartNew();
// parallel the iteration ( we can because concurrent dictionary is thread safe-ish
numbers.AsParallel().ForAll((number) =>
{
// add the key if it's not there with value of 1 and if it's there it use the lambda function to increment by 1
dictionary.AddOrUpdate(number, 1, (key, old) => old + 1);
});
mode = dictionary.Aggregate((x, y) => { return x.Value > y.Value ? x : y; }).Key;
sw.Stop();
Console.WriteLine($"Dictionary: found {mode} in {sw.ElapsedMilliseconds} ms.");
Console.ReadLine();
}
So far, Netmage's is the fastest I've found. The only thing I have been able to make that can beat it (at least with a valid range of 1 to 500,000,000) will only work with arrays ranging from 1 to 500,000,000 or smaller in value on my computer because I only have 8 GB of RAM. This prevents me from testing it with the full 1 to int.MaxValue range and I suspect it will fall behind in terms of speed at that size as it appears to struggle more and more with larger ranges. It uses the values as indexes and the value at those indexes as the occurrences. With 6 million randomly generated positive 16 bit integers, it is about 20 times as fast as my original method with both in Release Mode. It is only about 1.6 times as fast with 32 bit integers ranging from 1 to 500,000,000.
private static List<NumberCount> findMostCommon(List<int> integers)
{
List<NumberCount> answers = new List<NumberCount>();
int[] mostCommon = new int[_Max];
int max = 0;
for (int i = 1; i < integers.Count; i++)
{
int iValue = integers[i];
mostCommon[iValue]++;
int intVal = mostCommon[iValue];
if (intVal > 1)
{
if (intVal > max)
{
max++;
answers.Clear();
answers.Add(new NumberCount(iValue, max));
}
else if (intVal == max)
{
answers.Add(new NumberCount(iValue, max));
}
}
}
if (answers.Count < 1)
answers.Add(new NumberCount(0, -100)); // This -100 Occurrecnces value signifies that all values are equal.
return answers;
}
Perhaps a branching like this would be optiomal:
if (list.Count < sizeLimit)
answers = getFromSmallRangeMethod(list);
else
answers = getFromStandardMethod(list);
I want to effectively throttle an event stream, so that my delegate is called when the first event is received but then not for 1 second if subsequent events are received. After expiry of that timeout (1 second), if a subsequent event was received I want my delegate to be called.
Is there a simple way to do this using Reactive Extensions?
Sample code:
static void Main(string[] args)
{
Console.WriteLine("Running...");
var generator = Observable
.GenerateWithTime(1, x => x <= 100, x => x, x => TimeSpan.FromMilliseconds(1), x => x + 1)
.Timestamp();
var builder = new StringBuilder();
generator
.Sample(TimeSpan.FromSeconds(1))
.Finally(() => Console.WriteLine(builder.ToString()))
.Subscribe(feed =>
builder.AppendLine(string.Format("Observed {0:000}, generated at {1}, observed at {2}",
feed.Value,
feed.Timestamp.ToString("mm:ss.fff"),
DateTime.Now.ToString("mm:ss.fff"))));
Console.ReadKey();
}
Current output:
Running...
Observed 064, generated at 41:43.602, observed at 41:43.602
Observed 100, generated at 41:44.165, observed at 41:44.602
But I want to observe (timestamps obviously will change)
Running...
Observed 001, generated at 41:43.602, observed at 41:43.602
....
Observed 100, generated at 41:44.165, observed at 41:44.602
Okay,
you have 3 scenarios here:
1) I would like to get one value of the event stream every second.
means: that if it produces more events per second, you will get a always bigger buffer.
observableStream.Throttle(timeSpan)
2) I would like to get the latest event, that was produced before the second happens
means: other events get dropped.
observableStream.Sample(TimeSpan.FromSeconds(1))
3) you would like to get all events, that happened in the last second. and that every second
observableStream.BufferWithTime(timeSpan)
4) you want to select what happens in between the second with all the values, till the second has passed, and your result is returned
observableStream.CombineLatest(Observable.Interval(1000), selectorOnEachEvent)
Here's is what I got with some help from the RX Forum:
The idea is to issue a series of "tickets" for the original sequence to fire. These "tickets" are delayed for the timeout, excluding the very first one, which is immediately pre-pended to the ticket sequence. When an event comes in and there is a ticket waiting, the event fires immediately, otherwise it waits till the ticket and then fires. When it fires, the next ticket is issued, and so on...
To combine the tickets and original events, we need a combinator. Unfortunately, the "standard" .CombineLatest cannot be used here because it would fire on tickets and events that were used previousely. So I had to create my own combinator, which is basically a filtered .CombineLatest, that fires only when both elements in the combination are "fresh" - were never returned before. I call it .CombineVeryLatest aka .BrokenZip ;)
Using .CombineVeryLatest, the above idea can be implemented as such:
public static IObservable<T> SampleResponsive<T>(
this IObservable<T> source, TimeSpan delay)
{
return source.Publish(src =>
{
var fire = new Subject<T>();
var whenCanFire = fire
.Select(u => new Unit())
.Delay(delay)
.StartWith(new Unit());
var subscription = src
.CombineVeryLatest(whenCanFire, (x, flag) => x)
.Subscribe(fire);
return fire.Finally(subscription.Dispose);
});
}
public static IObservable<TResult> CombineVeryLatest
<TLeft, TRight, TResult>(this IObservable<TLeft> leftSource,
IObservable<TRight> rightSource, Func<TLeft, TRight, TResult> selector)
{
var ls = leftSource.Select(x => new Used<TLeft>(x));
var rs = rightSource.Select(x => new Used<TRight>(x));
var cmb = ls.CombineLatest(rs, (x, y) => new { x, y });
var fltCmb = cmb
.Where(a => !(a.x.IsUsed || a.y.IsUsed))
.Do(a => { a.x.IsUsed = true; a.y.IsUsed = true; });
return fltCmb.Select(a => selector(a.x.Value, a.y.Value));
}
private class Used<T>
{
internal T Value { get; private set; }
internal bool IsUsed { get; set; }
internal Used(T value)
{
Value = value;
}
}
Edit: here's another more compact variation of CombineVeryLatest proposed by Andreas Köpf on the forum:
public static IObservable<TResult> CombineVeryLatest
<TLeft, TRight, TResult>(this IObservable<TLeft> leftSource,
IObservable<TRight> rightSource, Func<TLeft, TRight, TResult> selector)
{
return Observable.Defer(() =>
{
int l = -1, r = -1;
return Observable.CombineLatest(
leftSource.Select(Tuple.Create<TLeft, int>),
rightSource.Select(Tuple.Create<TRight, int>),
(x, y) => new { x, y })
.Where(t => t.x.Item2 != l && t.y.Item2 != r)
.Do(t => { l = t.x.Item2; r = t.y.Item2; })
.Select(t => selector(t.x.Item1, t.y.Item1));
});
}
I was struggling with this same problem last night, and believe I've found a more elegant (or at least shorter) solution:
var delay = Observable.Empty<T>().Delay(TimeSpan.FromSeconds(1));
var throttledSource = source.Take(1).Concat(delay).Repeat();
This is the what I posted as an answer to this question in the Rx forum:
UPDATE:
Here is a new version that does no longer delay event forwarding when events occur with a time difference of more than one second:
public static IObservable<T> ThrottleResponsive3<T>(this IObservable<T> source, TimeSpan minInterval)
{
return Observable.CreateWithDisposable<T>(o =>
{
object gate = new Object();
Notification<T> last = null, lastNonTerminal = null;
DateTime referenceTime = DateTime.UtcNow - minInterval;
var delayedReplay = new MutableDisposable();
return new CompositeDisposable(source.Materialize().Subscribe(x =>
{
lock (gate)
{
var elapsed = DateTime.UtcNow - referenceTime;
if (elapsed >= minInterval && delayedReplay.Disposable == null)
{
referenceTime = DateTime.UtcNow;
x.Accept(o);
}
else
{
if (x.Kind == NotificationKind.OnNext)
lastNonTerminal = x;
last = x;
if (delayedReplay.Disposable == null)
{
delayedReplay.Disposable = Scheduler.ThreadPool.Schedule(() =>
{
lock (gate)
{
referenceTime = DateTime.UtcNow;
if (lastNonTerminal != null && lastNonTerminal != last)
lastNonTerminal.Accept(o);
last.Accept(o);
last = lastNonTerminal = null;
delayedReplay.Disposable = null;
}
}, minInterval - elapsed);
}
}
}
}), delayedReplay);
});
}
This was my earlier try:
var source = Observable.GenerateWithTime(1,
x => x <= 100, x => x, x => TimeSpan.FromMilliseconds(1), x => x + 1)
.Timestamp();
source.Publish(o =>
o.Take(1).Merge(o.Skip(1).Sample(TimeSpan.FromSeconds(1)))
).Run(x => Console.WriteLine(x));
Ok, here's one solution. I don't like it, particularly, but... oh well.
Hat tips to Jon for pointing me at SkipWhile, and to cRichter for the BufferWithTime. Thanks guys.
static void Main(string[] args)
{
Console.WriteLine("Running...");
var generator = Observable
.GenerateWithTime(1, x => x <= 100, x => x, x => TimeSpan.FromMilliseconds(1), x => x + 1)
.Timestamp();
var bufferedAtOneSec = generator.BufferWithTime(TimeSpan.FromSeconds(1));
var action = new Action<Timestamped<int>>(
feed => Console.WriteLine("Observed {0:000}, generated at {1}, observed at {2}",
feed.Value,
feed.Timestamp.ToString("mm:ss.fff"),
DateTime.Now.ToString("mm:ss.fff")));
var reactImmediately = true;
bufferedAtOneSec.Subscribe(list =>
{
if (list.Count == 0)
{
reactImmediately = true;
}
else
{
action(list.Last());
}
});
generator
.SkipWhile(item => reactImmediately == false)
.Subscribe(feed =>
{
if(reactImmediately)
{
reactImmediately = false;
action(feed);
}
});
Console.ReadKey();
}
Have you tried the Throttle extension method?
From the docs:
Ignores values from an observable sequence which are followed by another value before dueTime
It's not quite clear to me whether that's going to do what you want or not - in that you want to ignore the following values rather than the first value... but I would expect it to be what you want. Give it a try :)
EDIT: Hmmm... no, I don't think Throttle is the right thing, after all. I believe I see what you want to do, but I can't see anything in the framework to do it. I may well have missed something though. Have you asked on the Rx forum? It may well be that if it's not there now, they'd be happy to add it :)
I suspect you could do it cunningly with SkipUntil and SelectMany somehow... but I think it should be in its own method.
What you are searching for is the CombineLatest.
public static IObservable<TResult> CombineLatest<TLeft, TRight, TResult>(
IObservable<TLeft> leftSource,
IObservable<TRight> rightSource,
Func<TLeft, TRight, TResult> selector
)
that merges 2 obeservables, and returning all values, when the selector (time) has a value.
edit: john is right, that is maybe not the preferred solution
Inspired by Bluelings answer I provide here a version that compiles with Reactive Extensions 2.2.5.
This particular version counts the number of samples and also provide the last sampled value. To do this the following class is used:
class Sample<T> {
public Sample(T lastValue, Int32 count) {
LastValue = lastValue;
Count = count;
}
public T LastValue { get; private set; }
public Int32 Count { get; private set; }
}
Here is the operator:
public static IObservable<Sample<T>> SampleResponsive<T>(this IObservable<T> source, TimeSpan interval, IScheduler scheduler = null) {
if (source == null)
throw new ArgumentNullException(nameof(source));
return Observable.Create<Sample<T>>(
observer => {
var gate = new Object();
var lastSampleValue = default(T);
var lastSampleTime = default(DateTime);
var sampleCount = 0;
var scheduledTask = new SerialDisposable();
return new CompositeDisposable(
source.Subscribe(
value => {
lock (gate) {
var now = DateTime.UtcNow;
var elapsed = now - lastSampleTime;
if (elapsed >= interval) {
observer.OnNext(new Sample<T>(value, 1));
lastSampleValue = value;
lastSampleTime = now;
sampleCount = 0;
}
else {
if (scheduledTask.Disposable == null) {
scheduledTask.Disposable = (scheduler ?? Scheduler.Default).Schedule(
interval - elapsed,
() => {
lock (gate) {
if (sampleCount > 0) {
lastSampleTime = DateTime.UtcNow;
observer.OnNext(new Sample<T>(lastSampleValue, sampleCount));
sampleCount = 0;
}
scheduledTask.Disposable = null;
}
}
);
}
lastSampleValue = value;
sampleCount += 1;
}
}
},
error => {
if (sampleCount > 0)
observer.OnNext(new Sample<T>(lastSampleValue, sampleCount));
observer.OnError(error);
},
() => {
if (sampleCount > 0)
observer.OnNext(new Sample<T>(lastSampleValue, sampleCount));
observer.OnCompleted();
}
),
scheduledTask
);
}
);
}
I have the following code:
Task.Factory.ContinueWhenAll(items.Select(p =>
{
return CreateItem(p);
}).ToArray(), completedTasks => { Console.WriteLine("completed"); });
Is it possible to convert ContinueWhenAll to a synchronous method? I want to switch back between async and sync.
Edit: I should metnion that each of the "tasks" in the continuewhenall method should be executing synchronously.
If you want to leave your existing code intact and have a variable option of executing synchronously you should make these changes:
bool isAsync = false; // some flag to check for async operation
var batch = Task.Factory.ContinueWhenAll(items.Select(p =>
{
return CreateItem(p);
}).ToArray(), completedTasks => { Console.WriteLine("completed"); });
if (!isAsync)
batch.Wait();
This way you can toggle it programmatically instead of by editing your source code. And you can keep the continuation code the same for both methods.
Edit:
Here is a simple pattern for having the same method represented as a synchronous and async version:
public Item CreateItem(string name)
{
return new Item(name);
}
public Task<Item> CreateItemAsync(string name)
{
return Task.Factory.StartNew(() => CreateItem(name));
}
Unless am mistaken this is what you're looking for
Task.WaitAll(tasks);
//continuation code here
i think you can try this.
using TaskContinuationOptions for a simple scenario.
var taskFactory = new TaskFactory(TaskScheduler.Defau
var random = new Random();
var tasks = Enumerable.Range(1, 30).Select(p => {
return taskFactory.StartNew(() => {
var timeout = random.Next(5, p * 50);
Thread.Sleep(timeout / 2);
Console.WriteLine(#" 1: ID = " + p);
return p;
}).ContinueWith(t => {
Console.WriteLine(#"* 2: ID = " + t.Result);
}, TaskContinuationOptions.ExecuteSynchronously);
}).ToArray();
Task.WaitAll(tasks);
or using TPL Dataflow for a complex scenario.
var step2 = new ActionBlock<int>(i => {
Thread.Sleep(i);
Console.WriteLine(#"* 2: ID = " + i);
}, new ExecutionDataflowBlockOptions {
MaxDegreeOfParallelism = 1,
//MaxMessagesPerTask = 1
});
var random = new Random();
var tasks = Enumerable.Range(1, 50).Select(p => {
return Task.Factory.StartNew(() => {
var timeout = random.Next(5, p * 50);
Thread.Sleep(timeout / 2);
Console.WriteLine(#" 1: ID = " + p);
return p;
}).ContinueWith(t => {
Thread.Sleep(t.Result);
step2.Post(t.Result);
});
}).ToArray();
await Task.WhenAll(tasks).ContinueWith(t => step2.Complete());
await step2.Completion;
Is it possible to get result1 as a single linq expression? I understand that it may not be the best practise but I would just like to know how to do so out of curiousity.
result2 has a different answer but it correct too. However, it has a complexity of O(NlogN) as opposed to O(N).
void Main()
{
A[] a = new A[4]{new A(0,0,0),new A(1,1,0),new A(1,2,1),new A(1,2,0)};
/*
//Grossly inefficient: replaced
var tmpList = a.Where(x => (x.one == a.Max(y => y.one)));
var result1 = tmpList.First(x => (x.two == tmpList.Max(y => y.two)));
*/
var maxOneValue = a.Max(x => x.one);
var tmpList = a.Where(x => (x.one == maxOneValue));
var maxTwoValueOfTmpList = tmpList.Max(x => x.two);
var result1 = tmpList.First(x => (x.two == maxTwoValueOfTmpList));
//A: 1, 2, 1
var result2 = a.OrderBy(x => x.one)
.ThenBy(x => x.two)
.Last();
//A: 1, 2, 0
}
class A
{
public int one;
public int two;
public int three;
public A(int one, int two, int three)
{
this.one = one;
this.two = two;
this.three = three;
}
}
edit: I have edited by question and hence some answers may not tally.
This query gives the same result :
var result = a.OrderByDescending(x => x.one + x.two)
.First();
But then you could get items without max 'one' field..
This one should work :
var result = a.OrderByDescending(x => x.two)
.Where(x => (x.one == a.Max(y => y.one)))
.First();
maybe this solves your problem:
a.OrderBy(x => x.one + x.two).Last()
One way to do it is to implement IComparable<A> on your A class. Then your solution simply becomes:
var result1 = a.Max(); // 1,2,1
Here's how you would implement IComparable<A>:
class A : IComparable<A>
{
...
public int CompareTo(A other)
{
return this.one == other.one ? this.two - other.two : this.one - other.one;
}
}
Here is a demo: http://ideone.com/ufIcgf. The nice thing about this is that it still has a complexity of O(N), and is also fairly concise.