Mapping LINQ to F#
In my projects with F#, I often find that I know exactly what type of sequence transformation I want to run, yet I spend all of my time trying to find it!!! The problem is I’m used to query comprehensions in LINQ terminology. Select, Where and SelectMany are so ingrained into my programming they are practically done through muscle memory.
Unfortunately there is a disconnect between the naming convention used in LINQ and the ones used in F#. Some of the names are more intuitive than others. I’ve now spent enough time digging through Seq.fs that it’s time to draw up a table that maps various LINQ functions to their equivalent method in F#.
If nothing else, it will be a good table for me to come back to. Below is a list of many methods in Enumerable, mapped to the equivalent function in F#’s seq
- Aggregate –> fold
- All –> for_all
- Any –> exists
- Average –> average
- Cast –> cast
- Count –> length
- Distinct –> distinct
- ElementAt –> nth
- Empty –> empty
- First –> hd
- GroupBy –> group_by
- Max –> max
- Min –> min
- OrderBy –> sort_by
- Select –> map, mapi
- SelectMany –> concat, map_concat
- SequenceEqual –> compare
- Skip –> skip
- SkipWhile –> skip_while
- Sum –> sum
- Where –> filter
Below are the functions for which an equivalent was not found (or was quite simply overlooked). Most of these can be added with a combination of other simple transformations.
- DefaultIfEmpty
- Except
- FirstOrDefault
- GroupJoin
- Intersect
- Join
- Last
- LastOrDefault
- LongCount
- OfType
- Reverse
- Single
- SingleOrDefault
- Union
Comments
Anonymous
December 02, 2008
Funny: I was making the reverse mapping for myself a few weeks ago :-) Some subtleties arise from overloads. E.g. "Count" maps to "length" or "count_by" depending on the overload. Also, some functions in F# assume operators that LINQ cannot. Thus, LINQ cannot have an equivalent for the F# "sum" function. The equivalent of "Sum" in F# is "sum_by".Anonymous
December 08, 2008
The F# set functions only work on sets, not on IEnumerable. So "Enumerable.Except" is Set.diff, for example. For "First", it's either hd or find, depending on the overload with a predicate. FirstOrDefault is tryFind (returns 'a option). Some functions, like Reverse, exist only for List or Array types, not IEnumerable. Last and single aren't there, but as you note, it's trivial to add such things. I assume some of these things are merely oversight and probably will get "cleaned up" as part of F#'s productization. Or, I'm far too early to understand the decisions :). brilsmurf is right about sum, but it also applies to sum_by. These are "inline" functions, and have member constraints -- such things simply don't exist in C#. The + and Zero members are statically checked and compiled at the callsite. C# has to resort to defining tons of overloads for each such method -- one for each type(byte, short, int, etc...). Same goes for average[_by]. Pretty much any F# inline function will be impossible in C# (or very difficult at least).