2010-01-13 51 views
2

我有一個Point的集合,存儲在PointCollection中。從PointCollection中檢索對點?

我需要集合中的點來繪製線條。因此,例如,如果點集合有四個點,那將是兩條線,因爲我使用集合中的一對點來繪製線條。我正在尋找一種方法,最好使用linq和儘可能少的代碼行,以實質性地遍歷我的PointCollection,提取下一對可用的點,然後使用點對繪製線。有沒有辦法使用linq,lambda表達式或擴展方法來做到這一點?

謝謝。

+0

你能澄清所需的輸出?你說「如果一個點集合有四個點,那將是兩條線」,但我計算p1-p2,p1-p3,p1-p4,p2-p3,p2-p4和p3-p4。你的意思是*連續*對,在這種情況下是p1-p2和p3-p4? – itowlson 2010-01-13 06:25:10

回答

0

假設你只想順序對(注意,這並不他們 - 它只是列出了他們):

using System; 
using System.Collections; 
using System.Collections.Generic; 
using System.Windows; 
using System.Windows.Media; 
static class Program { 
    static void Main() { 
     PointCollection points = new PointCollection(); 
     points.Add(new Point(1, 1)); 
     points.Add(new Point(2, 2)); 
     points.Add(new Point(3, 3)); 
     points.Add(new Point(4, 4)); 
     points.Add(new Point(5, 5)); 
     points.Add(new Point(6, 6)); 
     points.Add(new Point(7, 7)); // odd number to test end 

     foreach (Tuple<Point, Point> pair in GetPairs(points)) { 
      Console.WriteLine("From " + pair.Value1 + " to " + pair.Value2); 
     } 
    } 
    public static IEnumerable<Tuple<Point, Point>> 
      GetPairs(PointCollection points) { 
     using (IEnumerator<Point> iter = points.GetEnumerator()) { 
      while (iter.MoveNext()) { 
       Point value1 = (Point)iter.Current; 
       if (!iter.MoveNext()) { yield break; } 
       yield return new Tuple<Point, Point>(value1, (Point)iter.Current); 
      } 
     } 
    } 
} 
public struct Tuple<T1, T2> { 
    public T1 Value1 { get { return value1; } } 
    public T2 Value2 { get { return value2; } } 
    private readonly T1 value1; 
    private readonly T2 value2; 
    public Tuple(T1 value1, T2 value2) { 
     this.value1 = value1; 
     this.value2 = value2; 
    } 
} 
0

另一種方法,使用LINQ位和遞歸:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace overflow2 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      List<Point> points = new List<Point>(); 
      points.Add(new Point(1, 1)); 
      points.Add(new Point(2, 2)); 
      points.Add(new Point(3, 3)); 
      points.Add(new Point(4, 4)); 
      points.Add(new Point(5, 5)); 
      points.Add(new Point(6, 6)); 
      points.Add(new Point(7, 7)); // odd number to test end 

      foreach (LineSegment<Point> linesegment in points.GetPairs()) 
       Console.WriteLine("From " + linesegment.Value1.ToString() + " to " + linesegment.Value2.ToString()); 

      Console.ReadLine(); 
     } 
    } 

    public class Point 
    { 
     public int x { get; set; } 
     public int y { get; set; } 

     public Point(int _x, int _y) 
     { 
      x = _x; 
      y = _x; 
     } 

     public override string ToString() 
     { 
      return string.Format("{0},{1}", x, y); 
     } 
    } 

    public class LineSegment<T> 
    { 
     public T Value1 { get; private set; } 
     public T Value2 { get; private set; } 

     public LineSegment(T value1, T value2) 
     { 
      Value1 = value1; 
      Value2 = value2; 
     } 
    } 

    public static class Util 
    { 
     public static List<LineSegment<Point>> GetPairs(this List<Point> points) 
     { 
      if (points.Count >= 2) 
      { 
       var pair = new LineSegment<Point>(points.Take(1).First(), points.Skip(1).Take(1).First()); 
       var res = new List<LineSegment<Point>>() { pair }; 
       res.AddRange(points.Skip(2).ToList().GetPairs()); // recursion 
       return res; 
      } 
      else 
       return new List<LineSegment<Point>>(); 
     } 
    } 
} 
1

下面是代碼的一個快速分段,以獲得配對。

var listOfPairs = points 
    .Select((p, i) => new {p, i}) 
    .GroupBy(x => x.i/2) 
    .Where(g => g.Skip(1).Any()) 
    .Select(g => g.Select(x => x.p).ToList()) 
    .ToList(); 

與foreach循環相比,如果您有數千個點,則這不是高性能的。


下面是使用捕獲變量的其他請求表單。

Point previous = points.FirstOrDefault(); 

List<Pair> pairs = points 
    .Skip(1) 
    .Select(p => 
    { 
    Pair result = new Pair(p, previous) 
    previous = p; 
    return result; 
    }) 
    .ToList(); 
+0

我需要澄清我的初始帖子。點的集合用於繪製線條,因此,結構如下: 如果集合中有四個點,則使用以下方法繪製線條: (1)點1和2用於繪製第一行 (2)用於繪製第二行的點2和3用於繪製第二行 (3)用於繪製第三行的點3和4 因此,即使集合中只有四個點,代表三條線。有沒有辦法爲我正在採用的方法提取對? – Chris 2010-01-13 16:59:15

1

你不使用你的的foreach並行假設,你可以使用:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Drawing; 

namespace PointDrawing 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      List<Point> points = new List<Point>(); 
      points.Add(new Point(1, 1)); 
      points.Add(new Point(2, 2)); 
      points.Add(new Point(3, 3)); 
      points.Add(new Point(4, 4)); 
      points.Add(new Point(5, 5)); 
      points.Add(new Point(6, 6)); 
      points.Add(new Point(7, 7)); 

      if (points.Count > 0) 
      { 
       Point src = points[0]; 
       points.ForEach(p => Draw(ref src, p)); 
      } 
     } 

     public static void Draw(ref Point p1, Point p2) 
     { 
      if (p1 != p2) 
      { 
       //Draw from p1 to p2 here 
      } 

      p1 = p2; //assign so that p2 is the next origin 
     } 
    } 
} 

這將與點的名單工作,但如果PointCollection是一個IEnumerable,你可以隨時添加了曾經如此有用的ForEach擴展到您的IEnumerable:

public static class Extensions 
{ 
    public static void ForEach<T>(this IEnumerable<T> source, Action<T> action) 
    { 
     foreach (var item in source) 
     { 
      action(item); 
     } 
    } 
}