Ix/Interactive Extensions

I’m a bit late to the party with this one – Ix or Interactive Extensions.

Available on NuGet via the Ix-Main package. This will give us the System.Interactive assembly.

Ix are basically a bunch of extension methods for IEnumerable and the
EnumerableEx class. I’m sure many of us have written IEnumerable extensions to supply a ForEach extension method or the likes. Well Ix gives us that and more.

In this post I will not be documenting each overload but will try to give an idea of what the methods might be used for and how to use them. Checking which overload is suitable is down to the reader.

Note: some of the examples may be less than useful, I will attempt to update with better examples as/when I come up with them.

Buffer

Basically takes an IEnumerable and creates an IEnumerable of IList of type T of the given buffer size.

IEnumerable<int> items = new int[] { 3, 5, 6, 2, 76, 45, 32, 1, 6, 3, 89, 100 };
IEnumerable<IList<int>> lists = items.Buffer(3);

The above would result in an IEnumerable with 4 ILists of type T each containing up to 3 items each. An overload of this method exists which allows you to skip a number of elements at the start of each buffer.

Case

Case is a static method on EnumerableEx and allows us to pass in an argument to compare against and an IDictionary of keys – which will be used to match with the argument passed into the Case method and it will return an IEnumerable relating to the values which appear in the dictionary against the given key. So for example

IDictionary<int, IEnumerable<string>> d = new Dictionary<int, IEnumerable<string>>
{
   {5, new[] {"Five"}},
   {4, new[] {"Four"}},
   {1, new[] {"One"}},
   {2, new[] {"Two"}},
   {3, new[] {"Three"}},
};

var matches = EnumerableEx.Case(() => 4, d);

In the above, matches will contain the IEnumerable of the values stored in the dictionary against the key 4, in other words the IEnumerable containing the string “Four”.

An overload of this method allows you to supply an IEnumerable to act as the default values should a match against the selector not be found.

Create

Create is a static method on the EnumerableEx class which allows us to create an IEnumerable from a IEnumerator (or via an overload from an IYielder).

Let’s assume we have a method that returns an IEnumerator of integers, here’s a mock up of such a method

private static IEnumerator<int> Factory()
{
   yield return 1;
   yield return 2;
   yield return 3;
   yield return 4;
}

Now using Ix we can create an IEnumerable of integers using

var items = EnumerableEx.Create(Factory);

Defer

As the name suggests Defer will defer the creation of an enumerable sequence until a call to GetEnumerator, so for example

var items = EnumerableEx.Defer(() => new [] { 3, 5, 6, 2 });

the code above will not call the enumerable factory method (in this case the anonymous method creating an array of integers) until the GetEnumerator is called.

Catch

Creates an IEnumerable sequence based on the source, but if the source has an exception will switch to the second IEnumerable.

A somewhat convoluted sample below

IEnumerable<int> GetNegatives()
{ 
   int[] items = new int[] { -1, -2, 0, -3 };
   for (int i = 0; i < items.Length; i++)
   {
      if (items[i] >= 0)
         throw new Exception();

      yield return items[i];
   }
}

IEnumerable<int> items = new int[] { 3, 5, 6, 2, 76, 45, 32, 1, 6, 3, 89, 100 };
IEnumerable<int> e = GetNegatives().Catch(items);

The above will create an IEnumerable e that contains -1, -2 and then the values from the items IEnumerable.

There are several overloads of the Catch method to check out.

Distinct

Returns an IEnumerable of the distinct values in a sequence

IEnumerable<int> items = new int[] { 3, 5, 6, 2, 76, 45, 32, 1, 6, 3, 89, 100 };
IEnumerable<int> distinct = items.Distinct();

The above will result in a sequence 3, 5, 6, 2, 76, 45, 32, 1, 89, 100 removing the duplicates.

DistinctUntilChanged

Returns consecutive distinct values

IEnumerable<int> items = new int[] { 3, 3, 3, 5, 5, 2, 76, 76, 100 };
IEnumerable<int> distinct = items.DistinctUntilChanged();

The above will return an sequence 3, 5, 2, 76, 100

Do

Several overloads of the Do method exist, we’ll just take a look at the one which takes an Action. Do will simply invoke some action on each item within the IEnumerable, so for example

IEnumerable<int> items = new int[] { 3, 5, 6, 2, 76 };
items.Do(Console.WriteLine);

the above code will simply call WriteLine on each integer within the items IEnumerable. However, this is lazy and hence we actually need to do something with the items returns enumerable.

DoWhile

The DoWhile method iterates over an IEnumerable whilst the supplied function is true, so for example

var items = new int[] { 3, 5, 6, 2 };

int i = 0;
var results = items.DoWhile(() => i++ < 2);
int len = results.Count();

If we run this code the len variable will be 12 as the DoWhile looped through the IEnumerable 3 times and the items array contained four items. So basically if we output to the console each item returned by results will see the array items output three times.

Expand

Expand, basically loops through the supplied IEnumerable (possibly infinitely if you do not use a Take or similar method to stop it). In essence is applies a selector function each time through the enumerable changing the values.

So imagine we have an array of values 1, 2 and 0 and apply Expand to this as follows

var items = new [] { 1, 2, 0 };
var results = items.Expand(i => new[] {i + 1}).Take(9);

what happens here is the output (if we ran results.ForEach(Console.WriteLine)) will output 1, 2, 0 (the values from items then 2, 3, 1 and finally 3, 4, 2. As you see each time we iterate through we add 1 to each element.

Finally

Finally can be used on a sequence so that an action may be invoked upon the termination or disposal, so for example the following will output the sequence to the console then output “Completed”

IEnumerable<int> items = new [] { 3, 5, 6, 2, 76 };

items.Finally(() => Console.WriteLine("Completed")).ForEach(Console.WriteLine);

For

The For method takes a source enumerable and applies a supplied enumerable to it, so a simple example might be

IEnumerable<int> items = new int[] { 3, 5, 6, 2, 76 };
EnumerableEx.For(items, i => new []{i + 1, i + 2});

In this case each item in the items enumerable will have the new []{i + 1, i + 2} applied to it, thus output for this would be

4, 5, 6, 7, 7, 8, 3, 4, 77, 78

the first item 3 in the source enumerable is sent to the For method and we get back a transformed value as two values 3 + 1 and then 3 + 2 and so on.

ForEach

ForEach will invoke an action on each item within an IEnumerable, so a simple example might be to just write a more compact foreach to write output to the console, i.e.

IEnumerable<int> items = new int[] { 3, 5, 6, 2, 76 };
items.ForEach(Console.WriteLine);

Generate

As the name suggests, Generate can be used to generate a sequence in a similar way to a for loop might be used, here’s an example which creates an IEnumerable with the range [10, 20]

EnumerableEx.Generate(10, i => i <= 20, i => i + 1, i => i)

The first argument is the starting value, then we have the condition to stop the generator, next we have the state update function, in this case we’re incrementing the state by 1, finally we have the result function, in this case we’re just using the supplied state value.

Hide

To quote the documentation “Returns Enumerable sequence with the same behavior as the original, but hiding the source identity”.

I’m not wholly sure of the use cases for this, but basically if we have the following

List<int> items = new List<int> { 3, 5, 6, 2, 76 };

if we used items.AsEnumerable() the type returned would still be a List however using

var result = items.Hide();

result will be a funky EnumerableEx type hiding the underlying implementation.

If

The If method is self-explanatory, it allows us to return an IEnumerable if a condition is met or it will return an empty sequence or the overload shown below acts as an if..else returning the alternate sequence

EnumerableEx.If(() => someCondition, new[] { 3, 5, 6, 2, 76 }, new [] {6, 7});

So it’s probably obvious that if the someCondition is true the first array is returned else the second array is returned.

IgnoreElements

A slightly odd one, which probably is more useful when used in combination with other methods. IgnoreElements returns a source sequence without its elements

IEnumerable<int> items = new [] { 3, 5, 6, 2, 76 };
var result = items.IgnoreElements();

result will be an empty sequence.

IsEmpty

As the name suggests, checks if the sequence is empty or not, obviously the following is not empty

IEnumerable<int> items = new [] { 3, 5, 6, 2, 76 };
var result = items.IsEmpty();

whereas the following will be empty

IEnumerable<int> items = new [] { 3, 5, 6, 2, 76 };
var result = items.IgnoreElements().IsEmpty();

Max

Returns the maximum value in the sequence

IEnumerable<int> items = new [] { 3, 5, 6, 2, 76 };
var result = items.Max();

this will result in the result being 76.

MaxBy

In essence MaxBy returns a sequence of values less than the supplied comparer, for example

IEnumerable<int> items = new [] { 3, 50, 6, 2, 76 };
items.MaxBy(i => i < 50).ForEach(Console.WriteLine);

this will create a sequence with values less than 50 and in this case write them to the console, thus outputting the values 3, 6 and 2.

Memoize

Memoize creates a buffer over the source sequence to ensure that if we were to iterate over the items multiple times we would not call the source multiple times. Obviously this would be useful if we’ve got the data from some file system or remote source to stop us retrieving the data multiple times, in use we have

IEnumerable<int> items = new [] { 3, 5, 6, 2, 76 };
var result = items.Memoize();

Min

Returns the minimum value in the sequence

IEnumerable<int> items = new [] { 3, 5, 6, 2, 76 };
var result = items.Max();

this will result in the result being 2.

MinBy

In essence MinBy returns a sequence of values greater than the supplied comparer, for example

IEnumerable<int> items = new [] { 3, 50, 6, 2, 76 };
items.MinBy(i => i < 50).ForEach(Console.WriteLine);

this will create a sequence with values greater or equal to 50 and in this case write them to the console, thus outputting the values 50 and 76.

OnErrorResumeNext

Concatenates the sequence with a second sequence regardless of whether an error occurred, used in situation where you might be getting data from a source that could fail, the example below just shows the syntax really as this wouldn’t need to use OnErrorResumeNext

IEnumerable<int> items = new [] { 3, 50, 6, 2, 76 };
var result = items.OnErrorResumeNext(new[] {9, 10});

result would contain the items sequence followed by the sequence { 9, 10 }.

Publish

To quote the documentation, “creates a buffer with a view over the source sequence, causing each enumerator to obtain access to the remainder of the sequence from the current index in the buffer”.

This allows the sequence to be shared via the buffer, in syntax terms this looks like

IEnumerable<int> items = new [] { 3, 50, 6, 2, 76 };
var buffer = items.Publish();

There is an overloaded method which allows you to supply a selector.

Repeat

Allows us to iterate through a sequence infinitely or with the overload, n times

IEnumerable<int> items = new [] { 3, 5, 6, 2, 76 };

// iterate over three times
items.Repeat(3).ForEach(Console.WriteLine);

// iterate infinitely
items.Repeat().ForEach(Console.WriteLine);

Retry

This method allows us to retry enumerating a sequence whilst an error occurs or via the overload we can specify the maximum number of retries

items.Retry(2);

Return

The Return method returns a single element as a sequence, for example

EnumerableEx.Return(1);

this creates an IEnumerable of integers with the single value 1 in it.

Scan

Scan generates a sequence using an accumulator, so for example

IEnumerable<int> items = new [] { 3, 5, 6, 2, 76 };
items.Scan((i, j) => i + j).ForEach(Console.WriteLine);

will pass 3 (i) and 5 (j) into the accumulator method the result will be 8 this will then be pass into the accumulator as i followed by 6 (j) and so on.

SelectMany

Several overloads exist, the one shown here simply projects each element of the sequence with a given sequence. For example the following simply projects the array { 5, 6 } over the original sequence

IEnumerable<int> items = new [] { 3, 50, 6, 2, 76 };
items.SelectMany(new [] { 5, 6 }).ForEach(Console.WriteLine);

This will output { 5, 6 } the number of times matching the number of elements in the items sequence, i.e. 5 times.

Share

A couple of overloads. This method creates a buffer with a shared view over the sequence so mutiple enumerators can be used to fetch the next element from the sequence, this example is a little convoluted

IEnumerable<int> items = new [] { 20, 10, 60, 30 };
items.Share(x => x.Zip(x, (a, b) => a - b)).ForEach(Console.WriteLine);

The same sequence is used on Zip and passed into Zip hence we’re zipping the sequence with itself, the result selector simply subtracts one value from the other. When output to the console this will write a sequence 10, 30 because the first item (20) has the second item (10) subtracted from it, as then the next item (60) has the final item (30) subtracted.

SkipLast

Allows us to skip/bypass n elements from the end of in the sequence, thus

IEnumerable<int> items = new [] { 3, 5, 6, 2, 76 };
items.SkipLast(2).ForEach(Console.WriteLine);

lists values 3, 5, 6 but not the last 2 items.

StartWith

StartWith starts the sequence with the newly supplied enumerable, for example

IEnumerable<int> items = new [] { 3, 5, 6, 2, 76 };
items.StartWith(new []{9, 10}).ForEach(Console.WriteLine);

will output the sequence 9, 10 then follow with the items sequence.

TakeLast

In essence the opposite of SkipLast, TakeLast results in a sequence on the last n items, such as

IEnumerable<int> items = new [] { 3, 5, 6, 2, 76 };
items.TakeLast(2).ForEach(Console.WriteLine);

which outputs 2 and 76.

Throw

With the Throw method we can create a sequence which throws an exception when we try to enumerate it, for example

EnumerableEx.Throw<int>(new NullReferenceException()).ForEach(Console.WriteLine);

will throw the NullReferenceException when ForEach attempts to enumerate the sequence.

Using

Using creates a sequence which has a resource who’s lifetime is determined by the sequence usage. The idea being the resource is created via the Using method’s first argument then passed to the second argument (in all likelihood to be used in some way) before an IEnumerable is returned. The key thing to note is the resource is not created until we use the returned IEnumerable, for example

IEnumerable<int> items = new [] { 3, 5, 6 };
IEnumerable<int> results = EnumerableEx.Using(() => new SomeDisposable(), resource => items);
results.ForEach(Console.WriteLine);

Assuming SomeDisposable implements IDisposable, when we call GetEnumerator the SomeDisposable is created and passed to the second argument – this rather simplistic example does nothing with the resource but hopefully you get the idea. We then return the IEnumerable and when the GetEnumerator completes the resources Dispose method is called.

While

Loops through the sequence whilst a condition is true, so for example

IEnumerable<int> items = new [] { 3, 5, 6, 2, 76 };

int i = 0;
EnumerableEx.While(() => i++ < 3, items).ForEach(Console.WriteLine);

will output the items sequence three times.