我有一個Point的集合,存儲在PointCollection中。從PointCollection中檢索對點?
我需要集合中的點來繪製線條。因此,例如,如果點集合有四個點,那將是兩條線,因爲我使用集合中的一對點來繪製線條。我正在尋找一種方法,最好使用linq和儘可能少的代碼行,以實質性地遍歷我的PointCollection,提取下一對可用的點,然後使用點對繪製線。有沒有辦法使用linq,lambda表達式或擴展方法來做到這一點?
謝謝。
我有一個Point的集合,存儲在PointCollection中。從PointCollection中檢索對點?
我需要集合中的點來繪製線條。因此,例如,如果點集合有四個點,那將是兩條線,因爲我使用集合中的一對點來繪製線條。我正在尋找一種方法,最好使用linq和儘可能少的代碼行,以實質性地遍歷我的PointCollection,提取下一對可用的點,然後使用點對繪製線。有沒有辦法使用linq,lambda表達式或擴展方法來做到這一點?
謝謝。
假設你只想順序對(注意,這並不畫他們 - 它只是列出了他們):
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;
}
}
另一種方法,使用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>>();
}
}
}
下面是代碼的一個快速分段,以獲得配對。
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();
我需要澄清我的初始帖子。點的集合用於繪製線條,因此,結構如下: 如果集合中有四個點,則使用以下方法繪製線條: (1)點1和2用於繪製第一行 (2)用於繪製第二行的點2和3用於繪製第二行 (3)用於繪製第三行的點3和4 因此,即使集合中只有四個點,代表三條線。有沒有辦法爲我正在採用的方法提取對? – Chris 2010-01-13 16:59:15
你不使用你的的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);
}
}
}
你能澄清所需的輸出?你說「如果一個點集合有四個點,那將是兩條線」,但我計算p1-p2,p1-p3,p1-p4,p2-p3,p2-p4和p3-p4。你的意思是*連續*對,在這種情況下是p1-p2和p3-p4? – itowlson 2010-01-13 06:25:10