Today I was reading some blogs and I came across this one: http://dotnet.dzone.com/news/functional-c-writing-partition?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+zones%2Fdotnet+%28.NET+Zone%29.
Mark Needham was writing a partition-function, that he came across in F#, in C#. He introduced a tuple class to contain two elements in one objects with easy access. He then created an extension method that takes an IEnumerable<T> and a Func<T, bool> and returns a tuple with the first value containing all elements in the original collection, that result in the predicate being true, and in the second value the other ones. Like he mentioned, he is creating two iterators to fill the tuple. I was thinking about a way to have the same tuple available, by using only one iterator.
I could only think about an approach using a caching infrastructure. So I quickly created one.
This is just the class. The important thing is that I manually pull the IEnumerator<T> in the GetNextValue-Method. This method is then invoked in the First and Second getters. These getters pull the elements and apply them to the predicate. Regarding to the predicates return value, the result is either yielded directly and cached in the own list or cached in the list of the other getter. So when the other getter is requested, it is returning the cashed values.
If GetEnumerator is called on the same getter again, the cached values will still be in the list and therefore not been pulled out manually of the enumerator. This will lead to enumerators side effects happening only once. The use of this cached IEnumerable<T> tuple need a change in the Partition-method, like shown below.
The enumerable is not been iterated. Instead, it is passed into the TupleOfTwoCachedCollections, which is left two handle pulling. The pull handles, which are parts.First and parts.Second can then be passed into the regular tuple. This tuple can then be iterated where it is created, like in the Main-method.
When this program is run, it will output the following.
Like expected, the first foreach pulls until it does not get anymore numbers, yields predicate matches and stores the other ones. So when the other foreach runs, it yields the cached ints, then checks for more numbers. Since there are no, no side effects happen anymore. The side effect is shown in the output as happening after the value is returned. This is caused by having placed the Console.Writeline after the yield return in the GetNumbers-method.
A cashing approach is also used in System.Interactive (Interactive Extensions) like Bart De Smet covers in this amazing article: http://community.bartdesmet.net/blogs/bart/archive/2010/01/07/more-linq-with-system-interactive-functional-fun-and-taming-side-effects.aspx!
I know that my “solution” is highly un-functional since it relies on object state (caches), but it does get the job done! At the end of the day, that is what matters. I also do not claim that this is a good way of doing it. It is just one way. You can get my code here: http://cid-e6c5570276bdbe2b.skydrive.live.com/self.aspx/%c3%96ffentlich/ExecutePartition.cs!
If you do not already, please follow me on twitter: www.twitter.com/halllo. Regards, Manuel Naujoks