Amb (Enumerable)

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));
}
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License