The name "Amb" is short for "ambiguous". This operator is described in a blog post by Jeffrey van Gogh.
Amb takes two or more sequences and returns the first sequence to respond. Since IEnumerable<T> seqences are blocking, the Amb operator uses parallel processing to detect which of the sequences yields the first item.
When any sequence yields an item, Amb returns that sequence. The other sequences passed to Amb are ignored.
Amb may be called as a static method:
[TestMethod]
public void Amb_CalledAsStaticMethod_ReturnsFastestSequence()
{
// This sequence yields after a delay
var first = new[] { 1, 2, 3 }.ToObservable().Delay(TimeSpan.FromMilliseconds(50)).ToEnumerable();
// This sequence yields immediately
var second = new[] { 4, 5, 6 };
var result = EnumerableEx.Amb(first, second);
Assert.IsTrue(result.SequenceEqual(second));
}
Amb may be called as an extension method, if it is only taking two sequences as input:
[TestMethod]
public void Amb_CalledAsTwoParameterExtensionMethod_ReturnsFastestSequence()
{
// This sequence yields after a delay
var first = new[] { 1, 2, 3 }.ToObservable().Delay(TimeSpan.FromMilliseconds(50)).ToEnumerable();
// This sequence yields immediately
var second = new[] { 4, 5, 6 };
var result = first.Amb(second);
Assert.IsTrue(result.SequenceEqual(second));
}
Amb may also be invoked on a sequence of sequences, as an extension method:
[TestMethod]
public void Amb_CalledAsExtensionMethod_ReturnsFastestSequence()
{
// This sequence yields after a delay
var first = new[] { 1, 2, 3 }.ToObservable().Delay(TimeSpan.FromMilliseconds(50)).ToEnumerable();
// This sequence yields immediately
var second = new[] { 4, 5, 6 };
var test = new[] { first, second };
var result = test.Amb();
Assert.IsTrue(result.SequenceEqual(second));
}
No matter how many sequences are provided to Amb, it always returns the sequence that is the fastest to yield its first item:
[TestMethod]
public void Amb_WithThreeSequences_ReturnsFastestSequence()
{
// This sequence yields after a 50ms delay
var first = new[] { 1, 2, 3 }.ToObservable().Delay(TimeSpan.FromMilliseconds(50)).ToEnumerable();
// This sequence yields after a 150ms delay
var second = new[] { 4, 5, 6 }.ToObservable().Delay(TimeSpan.FromMilliseconds(150)).ToEnumerable();
// This sequence yields after a 100ms delay
var third = new[] { 7, 8, 9 }.ToObservable().Delay(TimeSpan.FromMilliseconds(100)).ToEnumerable();
var result = EnumerableEx.Amb(first, second, third);
Assert.IsTrue(result.SequenceEqual(first));
}