How to Zip one IEnumerable with itself
- by wageoghe
I am implementing some math algorithms based on lists of points, like Distance, Area, Centroid, etc. Just like in this post: http://stackoverflow.com/questions/2227828/find-the-distance-required-to-navigate-a-list-of-points-using-linq
That post describes how to calculate the total distance of a sequence of points (taken in order) by essentially zipping the sequence "with itself", generating the sequence for Zip by offsetting the start position of the original IEnumerable by 1.
So, given the Zip extension in .Net 4.0, assuming Point for the point type, and a reasonable Distance formula, you can make calls like this to generate a sequence of distances from one point to the next and then to sum the distances:
var distances = points.Zip(points.Skip(1),Distance);
double totalDistance = distances.Sum();
Area and Centroid calculations are similar in that they need to iterate over the sequence, processing each pair of points (points[i] and points[i+1]). I thought of making a generic IEnumerable extension suitable for implementing these (and possibly other) algorithms that operate over sequences, taking two items at a time (points[0] and points[1], points[1] and points[2], ..., points[n-1] and points[n] (or is it n-2 and n-1 ...) and applying a function.
My generic iterator would have a similar signature to Zip, but it would not receive a second sequence to zip with as it is really just going to zip with itself.
My first try looks like this:
public static IEnumerable<TResult> ZipMyself<TSequence, TResult>(this IEnumerable<TSequence> seq, Func<TSequence, TSequence, TResult> resultSelector)
{
return seq.Zip(seq.Skip(1),resultSelector);
}
With my generic iterator in place, I can write functions like this:
public static double Length(this IEnumerable<Point> points)
{
return points.ZipMyself(Distance).Sum();
}
and call it like this:
double d = points.Length();
and
double GreensTheorem(Point p1, Point p1)
{
return p1.X * p2.Y - p1.Y * p2.X;
}
public static double SignedArea(this IEnumerable<Point> points)
{
return points.ZipMyself(GreensTheorem).Sum() / 2.0
}
public static double Area(this IEnumerable<Point> points)
{
return Math.Abs(points.SignedArea());
}
public static bool IsClockwise(this IEnumerable<Point> points)
{
return SignedArea(points) < 0;
}
and call them like this:
double a = points.Area();
bool isClockwise = points.IsClockwise();
In this case, is there any reason NOT to implement "ZipMyself" in terms of Zip and Skip(1)? Is there already something in LINQ that automates this (zipping a list with itself) - not that it needs to be made that much easier ;-)
Also, is there better name for the extension that might reflect that it is a well-known pattern (if, indeed it is a well-known pattern)?
Had a link here for a StackOverflow question about area calculation. It is question 2432428.
Also had a link to Wikipedia article on Centroid. Just go to Wikipedia and search for Centroid if interested.
Just starting out, so don't have enough rep to post more than one link,