Reputation: 2168
I have a collection of Points, stored in a PointCollection.
I need the points in the collection to draw lines. So, for example, if a point collection has four points, that will be two lines, as I use pairs of points in the collection to draw the line. I am looking for a way, preferably using linq, and as few lines of code as possible, to essentially iterate through my PointCollection, extracting the next available pairs of points, and then drawing the line using the pairs of points. Is there a way to do this using linq, lambda expressions, or extension method?
Thanks.
Upvotes: 2
Views: 2660
Reputation: 5036
Assuming you are not using parallelism on your foreach, you could use:
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
}
}
}
That would work with a list of point, but if PointCollection is an IEnumerable you could always add the ever so usefull ForEach extension to your IEnumerables:
public static class Extensions
{
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
{
foreach (var item in source)
{
action(item);
}
}
}
Upvotes: 1
Reputation: 110221
Here's a quick snip of code to get the pairs.
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();
This is not performant if you have thousands of points, compared to a foreach loop.
Here's the other requested form, using a captured variable.
Point previous = points.FirstOrDefault();
List<Pair> pairs = points
.Skip(1)
.Select(p =>
{
Pair result = new Pair(p, previous)
previous = p;
return result;
})
.ToList();
Upvotes: 1
Reputation: 509
another approach, using a bit of LINQ and recursion:
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>>();
}
}
}
Upvotes: 0
Reputation: 1064204
Assuming you just want sequential pairs (note this doesn't draw them - it just lists them):
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;
}
}
Upvotes: 0