如何邮编1 IEnumerable的与自身邮编、IEnumerable

2023-09-02 01:50:36 作者:桖铯沐莓

我实现基于点列出了一些数学算法,如距离,面积,质心等,就像在这篇文章:http://stackoverflow.com/questions/2227828/find-the-distance-required-to-navigate-a-list-of-points-using-linq

这交描述了如何通过实质上压缩和解序列与自身来计算一序列点(为了采取)的总距离,通过偏移的原始的IEnumerable的开始位置由1生成的序列邮编

因此​​,鉴于邮编扩展在.NET 4.0中,假设点的点类型,以及合理的距离公式,可以拨打电话这样产生距离的顺序从一个点到下一个,然后求和距离:

  VAR距离= points.Zip(points.Skip(1),距离);
双totalDistance = distances.Sum();
 

面积和质心计算是在他们需要遍历序列,处理每对点相似(点[i]和点[I + 1])。我想使一个通用的IEnumerable延伸适用于实现这些(和可能其它)的算法工作在序列,考虑两个项目的时间(点[0]和点[1],点[1]和点[2], ......,点[N-1]和点[n]的(或者是它的n-2和n-1,...),并应用一个函数。

我的通用的迭代将有一个类似的签名邮编,但它不会收到第二个序列与压缩,因为它真的只是要压缩与本身。

我的第一次尝试是这样的:

 公共静态的IEnumerable< TResult> ZipMyself< TSequence,TResult>(这IEnumerable的< TSequence>序列,Func键和LT; TSequence,TSequence,TResult> resultSelector)
{
  返回seq.Zip(seq.Skip(1),resultSelector);
}
 
一般人纳税证明如何打印 图示指引来了

开始编辑: 看到回复后,我已经实现配对与明确使用下面的枚举是这样的:

 公共静态的IEnumerable< TResult>成对< TSequence,TResult>(这IEnumerable的< TSequence>序列,Func键和LT; TSequence,TSequence,TResult> resultSelector)
{
  TSequence preV =默认(TSequence);
  使用(IEnumerator的< TSequence> E = seq.GetEnumerator())
  {
    如果(e.MoveNext())preV = e.Current;

    而(e.MoveNext())收益率的回报resultSelector(preV,preV = e.Current);
  }
}
 

虽然肯定比我最初的版本比较复杂,通过输入序列这一个迭代一次,而原来的迭代两次。

编辑完

使用我的地方通用的迭代,我可以写这样的功能:

 公共静态双长度(这IEnumerable的<点>分)
{
  返回points.ZipMyself(距离).SUM();
}
 

和调用它是这样的:

 双D = points.Length();
 

 双GreensTheorem(点P1,P1点)
{
  返回p1.X * p2.Y  -  p1.Y * p2.X;
}

公共静态双SignedArea(这IEnumerable的<点>分)
{
  返回points.ZipMyself(GreensTheorem).SUM()/ 2.0
}

公共静态双区(这IEnumerable的<点>分)
{
  返回Math.Abs​​(points.SignedArea());
}

公共静态布尔IsClockwise(这IEnumerable的<点>分)
{
  返回SignedArea(点)< 0;
}
 

和调用它们像这样的:

 双A = points.Area();
布尔isClockwise = points.IsClockwise();
 

在这种情况下,没有任何理由不执行ZipMyself中邮方面和Skip(1)?有一些已经在LINQ中的自动完成此(荏苒一个列表本身) - 不,它需要做出更加容易; - )

此外,有没有为扩展更好的名字可能反映,这是一个公知的图案(如,它确实是一种公知的图案)?

有一个链接这里了解面积计算一个计算器问题。这是问题2432428。

也有一个链接到质心维基百科的文章。只要到维基百科,如果有兴趣的搜索质心。

刚刚起步,所以没有足够的代表处发布多个链接。

开始修改

有关完整性,如果有人送过来寻找距离,面积,或质心后,这里是我的功能,接受职位类型的列表(假设封闭区和心)并返回距离(沿),区和质心位置:

 公共结构的位置
{
  公共双X;
  公共双Y;

  静态公共双距离(位置P1,​​位置P2)
  {
    双DX = p2.X  -  p1.X;
    双DY = p2.Y  -  p1.Y;
    返回的Math.sqrt(DX * DX + DY * DY);
  }
}

公共静态类PointMath
{
  公共静态双距离(IEnumerable的<位置> PTS)
  {
    返回pts.Pairwise((P1,P2)=> Position.Distance(P1,P2))。萨姆();
  }

  私有静态布尔IsClockwise(IEnumerable的<位置> PTS)
  {
    返回SignedArea(PTS)< 0;
  }

  私有静态双SignedArea(IEnumerable的<位置> PTS)
  {
    返回pts.Pairwise((P1,P2)=>(p1.X * p2.Y  -  p1.Y * p2.X))萨姆()/ 2.0。
  }

  公共静态双区(IEnumerable的<位置> PTS)
  {
    返回Math.Abs​​(SignedArea(PTS));
  }

  公共静态位置重心(IEnumerable的<位置> PTS)
  {
    双A = SignedArea(PTS);

    变种C = pts.Pairwise((P1,P2)=>新建
                                      {
                                        X =(p1.X + p2.X)*(p1.X * p2.Y  -  p2.X * p1.Y),
                                        Y =(p1.Y + p2.Y)*(p1.X * p2.Y  -  p2.X * p1.Y)
                                      })
                .Aggregate((T1,T2)=>新建
                                       {
                                         X = t1.x + t2.x,
                                         Y = t1.y + t2.y
                                       });

    返回新的位置(1.0 /(A * 6.0)* CX,1.0 /(A * 6.0)* CY);
  }
}
 

你的看法吧。

编辑完

解决方案   

此外,有没有为扩展更好的名字可能反映,这是一个公知的图案(如,它确实是一种公知的图案)?

是 - 它也被称为成对。已经做过,例如here.此外,还有已在here在SO 。

成对现在可以在拉链的.NET 4.0条款的实施,为你指出。这似乎是一个LINQ到对象解决方案,合理的方法,但有一个基于.NET v3.5版本使用的版本也可能是更有用更广泛的受众,在这一点上。

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);
}

Begin edit: After seeing the responses, I have implemented Pairwise with explicit use of the underlying Enumerator like this:

public static IEnumerable<TResult> Pairwise<TSequence, TResult>(this IEnumerable<TSequence> seq, Func<TSequence, TSequence, TResult> resultSelector)
{
  TSequence prev = default(TSequence);
  using (IEnumerator<TSequence> e = seq.GetEnumerator())
  {
    if (e.MoveNext()) prev = e.Current;

    while (e.MoveNext()) yield return resultSelector(prev, prev = e.Current);
  }
}

While certainly more complicated than my initial version, this one iterates through the input sequence once whereas the the original iterates twice.

End edit

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.

Begin edit

For completeness, if anyone gets here after searching for Distance, Area, or Centroid, here are my functions that accept a list of Position types (assumed closed for Area and Centroid) and return the Distance(along), Area, and Centroid of the Positions:

public struct Position
{
  public double X;
  public double Y;

  static public double Distance(Position p1, Position p2)
  {
    double dx = p2.X - p1.X;
    double dy = p2.Y - p1.Y;
    return Math.Sqrt(dx*dx + dy*dy);
  }
}

public static class PointMath
{
  public static double Distance(IEnumerable<Position> pts)
  {
    return pts.Pairwise((p1, p2) => Position.Distance(p1, p2)).Sum();
  }

  private static bool IsClockwise(IEnumerable<Position> pts)
  {
    return SignedArea(pts) < 0;
  }

  private static double SignedArea(IEnumerable<Position> pts)
  {
    return pts.Pairwise((p1, p2) => (p1.X * p2.Y - p1.Y * p2.X)).Sum() / 2.0;
  }

  public static double Area(IEnumerable<Position> pts)
  {
    return Math.Abs(SignedArea(pts));
  }

  public static Position Centroid(IEnumerable<Position> pts)
  {
    double a = SignedArea(pts);

    var  c = pts.Pairwise((p1, p2) => new 
                                      { 
                                        x = (p1.X + p2.X) * (p1.X * p2.Y - p2.X * p1.Y), 
                                        y = (p1.Y + p2.Y) * (p1.X * p2.Y - p2.X * p1.Y)   
                                      })
                .Aggregate((t1, t2) => new 
                                       { 
                                         x = t1.x + t2.x, 
                                         y = t1.y + t2.y 
                                       });

    return new Position(1.0 / (a * 6.0) * c.x, 1.0 / (a * 6.0) * c.y);
  }
}

Feel free to comment.

End edit

解决方案

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)?

Yes - it is also known as Pairwise. It has been done before, for example here. There also has been a question about it before here on SO.

Pairwise can now be implemented in terms of Zip for .NET 4.0, as you point out. This seems like a reasonable approach for a LINQ to Objects solution, although having a version that works on .NET v3.5 too is probably more useful to a wider audience at this point.