C# 从列表的公共属性值创建字典<;对象>;

C# 从列表的公共属性值创建字典<;对象>;,c#,linq,list,dictionary,C#,Linq,List,Dictionary,假设我们有一个\u2dline对象列表 public class _2DLine { public double X1 { get; set; } public double Y1 { get; set; } public double X2 { get; set; } public double Y2 { get; set; } } var L1 = new _2DLine { X1 = 0, Y1 = 0, X2 = 100, Y2 = 100 }; var

假设我们有一个
\u2dline
对象列表

public class _2DLine
{
    public double X1 { get; set; }
    public double Y1 { get; set; }
    public double X2 { get; set; }
    public double Y2 { get; set; }
}

var L1 = new _2DLine { X1 = 0, Y1 = 0, X2 = 100, Y2 = 100 };
var L2 = new _2DLine { X1 = 50, Y1 = 50, X2 = 200, Y2 = 200 };
var L3 = new _2DLine { X1 = 0, Y1 = 0, X2 = 200, Y2 = 200};
var L4 = new _2DLine { X1 = 100, Y1 = 100, X2 = 50, Y2 = 50};

var MyLines = new List<_2DLine>
{
    L1,
    L2,
    L3,
    L4
}
最终结果如下:

  Key              |    Value
-----------------------------------
_2DPoint(0,0)      |   { L1, L3 }
_2DPoint(100,100)  |   { L1, L4 }
_2DPoint(50,50)    |   { L2, L4 }
_2DPoint(200,200)  |   { L2, L3 }

将线投影到点和线的展平序列,然后按点分组序列(我使用匿名类型,因为它们实现了Equals和GetHashCode),并创建字典:

var result = MyLines.SelectMany(l => new[] { 
                                   new { X = l.X1, Y = l.Y1 },
                                   new { X = l.X2, Y = l.Y2 }
                                }, (l,p) => new { Point = p, Line = l })
                   .GroupBy(x => x.Point)
                   .ToDictionary(g => new _2DPoint { X = g.Key.X, Y = g.Key.Y },
                                 g => g.Select(x => x.Line).ToList());

建议-使用点作为线的起点和终点,而不是四个坐标。还可以改进命名。不要从下划线开始类名,对局部变量使用camelCase名称。例如

public class Line
{
    public Line(double startX, double startY, double endX, double endY)
        : this(new Point(startX, startY), new Point(endX, endY))
    {
    }

    public Line(Point start, Point end)
    {
        Start = start;
        End = end;
    }
    public Point Start { get; private set; }
    public Point End { get; private set; }
}
我还将创建point作为value对象,并重写Equals和GetHashCode方法,以按值比较点:

public class Point
{
    public Point(double x, double y)
    {
        X = x;
        Y = y;
    }
    public double X { get; private set; }
    public double Y { get; private set; }

    public override bool Equals(object obj)
    {
        Point other = obj as Point;
        if (other == null)
            return false;

        return X == other.X && Y == other.Y;
    }

    public override int GetHashCode()
    {            
        return X.GetHashCode() * 19 + Y.GetHashCode();
    }
}
现在,创建行列表如下所示:

var lines = new List<Line> {
    new Line(0, 0, 100, 100),
    new Line(50, 50, 200, 200),
    new Line(0, 0, 200, 200),
    new Line(100, 100, 50, 50)
};

这似乎是一个简单的要求。是什么阻碍了你的解决方案?我看这里没有问题。@user414076我不知道如何创建字典。@Vahid:指定该过程的哪个步骤比较困难。创建字典?指定字典的内容?过滤输入集以确定进入字典的内容?是代码给了您一个问题,还是算法?如果让我来推断,我想你脑子里没有一个好的算法。但也许是密码。我不知道,因为你还没有问任何问题。@Vahid我更新了答案,并对查询提出了一些意见和改进代码的建议:)哇,Sergey,这正是我想要的解决方案。这里有一些非常出色的家伙。非常感谢您的更新,WPF中的
确实干扰了
,这就是我选择
\u 2DLine
的原因。对于其他类,正如你所说,我使用的是camelCase。
var lines = new List<Line> {
    new Line(0, 0, 100, 100),
    new Line(50, 50, 200, 200),
    new Line(0, 0, 200, 200),
    new Line(100, 100, 50, 50)
};
var points = lines.SelectMany(l => new[] { l.Start, l.End },
                              (l, p) => new { Line = l, Point = p })
                  .GroupBy(x => x.Point)
                  .ToDictionary(g => g.Key, g => g.Select(x => x.Line).ToList());