简体   繁体   English

从列表的公共属性值创建字典<Object>

[英]Create a dictionary from the common property values of a List<Object>

Let's say we have a list of _2DLine objects. 假设我们有一个_2DLine对象的列表。

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
}

As you can see, some of the lines have points in common. 如您所见,有些线有共同点。 How can we extract all the points from this list into a dictionary so that for a specific _2DPoint(X,Y) we will have a list of the lines entering or exiting that point. 我们如何从列表中提取所有点到字典中,以便对于特定的_2DPoint(X,Y)我们将获得进入或退出该点的线的列表。

var MyPoints = new Dictionary<_2DPoint, List<_2DLine>>();

public class _2DPoint
{
    public double X { get; set; }
    public double Y { get; set; }
}

The final result would be like this: 最终结果将是这样的:

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

Project lines to flattened sequence of points and lines, then group sequence by points (I use anonymous types, because they have implemented Equals and GetHashCode) and create dictionary: 将线投影到点和线的序列平整,然后按点对序列进行分组(我使用匿名类型,因为它们已经实现了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());

Suggestion - use your points as start and end of lines, instead having four coordinates. 建议-将点用作线的起点和终点,而不要使用四个坐标。 Also improve naming. 也改善命名。 Don't start class names from underscore, use camelCase names for local variables. 不要从下划线开始类名,而将camelCase名称用作局部变量。 Eg 例如

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

I would also create point as value object and override Equals and GetHashCode methods to compare points by their values: 我还将创建点作为值对象,并覆盖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();
    }
}

Now creating list of lines looks like: 现在创建行列表如下所示:

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

And points dictionary creation: 并指出字典的创建:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM