2010-01-13 7 views
2

J'ai une collection de Points, stockés dans un PointCollection.Récupérer des paires de points de PointCollection?

J'ai besoin des points de la collection pour tracer des lignes. Ainsi, par exemple, si une collection de points a quatre points, ce sera deux lignes, car j'utilise des paires de points dans la collection pour dessiner la ligne. Je cherche un moyen, de préférence en utilisant linq, et aussi peu de lignes de code que possible, de parcourir essentiellement mon PointCollection, d'extraire les paires de points disponibles, puis de dessiner la ligne en utilisant les paires de points. Existe-t-il un moyen d'utiliser linq, des expressions lambda ou une méthode d'extension?

Merci.

+0

Pourriez-vous préciser la sortie désirée? Vous dites "si une collection de points a quatre points, ce sera deux lignes", mais je compte p1-p2, p1-p3, p1-p4, p2-p3, p2-p4 et p3-p4. Voulez-vous dire * paires * consécutives, dans ce cas p1-p2 et p3-p4? – itowlson

Répondre

0

En supposant que vous voulez juste paires séquentielles (noter que cela ne les pas tirer - il les énumère seulement):

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

une autre approche, en utilisant un peu de LINQ et récursion:

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

Voici un petit bout de code pour obtenir les paires.

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

Ce n'est pas si vous avez performant des milliers de points, par rapport à une boucle foreach.


Voici l'autre formulaire requis, en utilisant une variable capturée.

Point previous = points.FirstOrDefault(); 

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

Je dois clarifier mon message initial. La collection de points est utilisée pour dessiner des lignes, donc, la structure est la suivante: S'il y a quatre points dans la collection, alors je dessinerais la ligne (s) en utilisant l'approche suivante: (1) Point 1 et 2 utilisé pour dessiner la première ligne (2) Point 2 et 3 utilisés pour dessiner la deuxième ligne (3) Point 3 et 4 utilisés pour dessiner la troisième ligne Ainsi, même s'il n'y a que quatre points dans la collection, ces points représenter trois lignes. Existe-t-il un moyen d'extraire les paires pour l'approche que je prends? – Chris

1

En supposant que vous n'utilisez pas le parallélisme sur votre foreach, vous pouvez utiliser:

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

Cela fonctionnerait avec une liste de points, mais si PointCollection est un IEnumerable vous pouvez toujours ajouter le toujours si extension ForEach utile à vos IEnumerables:

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