F# has a bunch of standard sequence operators I have come to know and love from my experience with Mathematica. F# is getting lots of my attention now, and when it is in general release, I intend to use it frequently.
Right now, since F# isn't yet in general release, I can't really use it in production code. LINQ implements some of these operators using SQL-like names (e.g. 'select' is 'map', and 'where' is 'filter'), but I can find no implementation of 'fold', 'iter' or 'partition'.
Has anyone seen any C# implementation of standard sequence operators? Is this something someone should write?
If you look carefully, many Seq operations have a LINQ equivalent or can be easily derived. Just looking down the list...
Seq.append = Concat<TSource>(IEnumerable<TSource> second)
Seq.concat = SelectMany<IEnumerable<TSource>, TResult>(s => s)
Seq.distinct_by = GroupBy(keySelector).Select(g => g.First())
Seq.exists = Any<TSource>(Func<TSource, bool> predicate)
Seq.mapi = Select<TSource, TResult>(Func<TSource, Int32, TResult> selector)
Seq.fold = Aggregate<TSource, TAccumulate>(TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> func)
List.partition
is defined like this:
Split the collection into two collections, containing the elements for which the given predicate returns
true
andfalse
respectively
Which we can implement using GroupBy and a two-element array as a poor-man's tuple:
public static IEnumerable<TSource>[] Partition<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
return source.GroupBy(predicate).OrderByDescending(g => g.Key).ToArray();
}
Element 0 holds the true values; 1 holds the false values. GroupBy is essentially Partition on steroids.
And finally, Seq.iter
and Seq.iteri
map easily to foreach:
public static void Iter<TSource>(this IEnumerable<TSource> source, Action<TSource> action)
{
foreach (var item in source)
action(item);
}
public static void IterI<TSource>(this IEnumerable<TSource> source, Action<Int32, TSource> action)
{
int i = 0;
foreach (var item in source)
action(i++, item);
}
Aggregate
Tell use what iter
and partition
do, and we might fill in the blanks. I'm guessing iter=SelectMany
and partition might involve Skip
/Take
?
(update) I looked up Partition - here's a crude implementation that does some of it:
using System;
using System.Collections.Generic;
static class Program { // formatted for space
// usage
static void Main() {
int[] data = { 1, 2, 3, 4, 5, 6 };
var qry = data.Partition(2);
foreach (var grp in qry) {
Console.WriteLine("---");
foreach (var item in grp) {
Console.WriteLine(item);
}
}
}
static IEnumerable<IEnumerable<T>> Partition<T>(
this IEnumerable<T> source, int size) {
int count = 0;
T[] group = null; // use arrays as buffer
foreach (T item in source) {
if (group == null) group = new T[size];
group[count++] = item;
if (count == size) {
yield return group;
group = null;
count = 0;
}
}
if (count > 0) {
Array.Resize(ref group, count);
yield return group;
}
}
}
iter exists as a method in the List class which is ForEach
otherwise :
public static void iter<T>(this IEnumerable<T> source, Action<T> act)
{
foreach (var item in source)
{
act(item);
}
}
ToLookup would probably be a better match for List.partition:
IEnumerable<T> sequence = SomeSequence();
ILookup<bool, T> lookup = sequence.ToLookup(x => SomeCondition(x));
IEnumerable<T> trueValues = lookup[true];
IEnumerable<T> falseValues = lookup[false];
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With