【问题标题】:Create a dictionary from the common property values of a List<Object>从 List<Object> 的公共属性值创建字典
【发布时间】:2014-05-30 21:42:31
【问题描述】:

假设我们有一个_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
}

如您所见,有些线条有共同点。 我们如何将这个列表中的所有点提取到字典中,以便对于特定的_2DPoint(X,Y),我们将获得进入或退出该点的行的列表。

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

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

最终的结果是这样的:

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

【问题讨论】:

  • 这似乎是一个简单的要求。是什么阻碍了您的解决方案?我在这里没有看到任何问题。
  • @user414076 我很困惑如何创建该字典。
  • @Vahid:指定该过程的哪个步骤是困难的。创建字典?指定字典的内容?过滤输入集以确定字典中的内容?
  • 是代码给你带来了问题,还是算法?如果让我推断,我认为你没有一个好的算法。但也许是代码。我不知道,因为你还没有问过问题。
  • @Vahid 我更新了一些关于查询和改进代码建议的 cmets 的答案 :)

标签: c# linq list dictionary


【解决方案1】:

将线投影到扁平的点和线序列,然后按点分组(我使用匿名类型,因为它们实现了 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());

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

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

我还将创建点作为值对象并覆盖 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)
};

并点字典创建:

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

【讨论】:

  • 哇,谢尔盖,正是我想要的解决方案。 SO中有一些非常出色的人。
  • 非常感谢您的更新,Line 确实干扰了 WPF 中的Line,这就是我选择_2DLine 的原因。正如你所说,对于我正在使用 camelCase 的其他课程。
猜你喜欢
  • 2022-12-07
  • 1970-01-01
  • 2023-01-04
  • 2020-09-02
  • 2017-01-28
  • 1970-01-01
  • 2019-04-06
  • 2010-12-10
  • 2020-06-04
相关资源
最近更新 更多