Skip to content

Instantly share code, notes, and snippets.

@mrange
Last active January 1, 2024 22:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mrange/b501838e5edcec319b7881de06ae5a2a to your computer and use it in GitHub Desktop.
Save mrange/b501838e5edcec319b7881de06ae5a2a to your computer and use it in GitHub Desktop.
Examples IEnumerable implementing a fibonacci series
// Example on the "easy" way to generate the fibonacci sequence
// https://en.wikipedia.org/wiki/Fibonacci_number
// Take the first 20 fibonacci numbers and print them
// the "easy" way.
foreach(var n in Fibonacci().Take(20))
{
Console.WriteLine(n);
}
// How to implement the fibonacci sequence as IEnumerable
// the "easy" way
// IEnumerable is an abstraction of a sequence
// in this case a sequence of fibonacci numbers
static IEnumerable<long> Fibonacci()
{
long previous = 1;
long current = 0;
// This looks like an infinite loop which normally
// would either cause program not to terminate
// or run out of memory
// However, IEnumerable is a lazy enumerator
// meaning it generates only 1 element at a time
// and waiting until asked by the consumer for
// another value
while(true)
{
// Compute new current by adding the previous
// and the current value together
// Store the previous current value as previous
var tmp = current;
current = tmp+previous;
previous = tmp;
// yield return current value as next element
// in the IEnumerable, yield implies the execution
// stops until the consumer asks for a new value
yield return current;
}
}
using System.Collections;
// Example on the "hard" way to generate the fibonacci sequence
// https://en.wikipedia.org/wiki/Fibonacci_number
// Take the first 20 fibonacci numbers and print them
// the "hard" way.
// Normally we do foreach but this what the compiler
// generates for you
// e is an IEnumerator, as that is IDisposable we should
// use using to ensure the Dispose is always executed
using var e = new FibonacciEnumerable().Take(20).GetEnumerator();
// Loop as long as MoveNext returns true
while (e.MoveNext())
{
// As MoveNext returned true e.Current has a valid value
Console.WriteLine(e.Current);
}
// How to implement the fibonacci sequence as IEnumerable
// the "hard" way
// IEnumerable is an abstraction of a sequence
// in this case a sequence of fibonacci numbers
class FibonacciEnumerable : IEnumerable<long>
{
// Create an enumerator and return it
public IEnumerator<long> GetEnumerator() =>
new FibonacciEnumerator();
// IEnumerable<T> extends IEnumerable which is the
// .NET 1.0 (about year 2000) interface so we need to
// implement a that GetEnumerator as well. Just call the
// the actual GetEnumerator implementation
// It looks recursive but as this is a private
// implementation of an interface it calls the GetEnumerator
// above
IEnumerator IEnumerable.GetEnumerator() =>
GetEnumerator();
}
// The enumerator does the actual work
class FibonacciEnumerator : IEnumerator<long>
{
// To compute the fibonacci sequence we track
// the previous value and the current value
long _previous = 1;
long _current = 0;
// Current is used to query the current value of the
// enumerator. You may only call Current if
// MoveNext returned true
public long Current => _current;
// MoveNext typical does most of the work
public bool MoveNext()
{
// Compute new current by adding the previous
// and the current value together
// Store the previous current value as previous
var tmp = _current;
_current = tmp + _previous;
_previous = tmp;
return true;
}
// Reset is used to restore the enumerator to the initial
// state before the iteration. Not commonly used IMHO
public void Reset()
{
_previous = 1;
_current = 0;
}
// Some enumerators iterate over files and network resources
// We therefore need a way to dispose them when the iteration
// is done in order to avoid memory and resource leaks
public void Dispose()
{
// In this case no specific dispose is needed
}
// IEnumerator<T> extends IEnumerator which is the
// .NET 1.0 (about year 2000) interface so we need to
// implement that Current as well. Just call the
// the actual Current implementation
// It looks recursive but as this is a private
// implementation of an interface it calls the Current
// above
object IEnumerator.Current => Current;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment