代码之家  ›  专栏  ›  技术社区  ›  drharris

用LINQ将X、Y连接到点中

  •  2
  • drharris  · 技术社区  · 14 年前

    我似乎有点固执己见,但我在林肯的经验不太好。基本上,我有这样的代码:

    public class Point
    {
        public int X { get; set; }
        public int Y { get; set; }
    }
    
    public class B
    {
        public List<Point> Points { get; set; }
        public B(IEnumerable<int> Xs, IEnumerable<int> Ys)
        {
            // How to best combine Xs and Ys into Points ?
        }
    }
    

    现在,如何填写该构造函数来正确地联接这些集合?我通常会用 .Join() ,但没有要联接的内部键。它还应该能够处理一个数组中元素比另一个少或为空的可能性(不应该发生,但这是可能的)。

    2 回复  |  直到 14 年前
        1
  •  4
  •   LBushkin    14 年前

    在C 4中,您可以使用 Zip operator :

    var result = Xs.Zip( Ys, (a,b) => new Point(a,b) );
    

    在C 3中,您可以使用 ElementAt 在选择执行相同操作的序列之一上:

    var result = Xs.Select( (x,i) => new Point( x, Ys.ElementAt(i) );
    

    第二个选项的主要问题是 要素 可能很贵,如果 IEnumerable 集合本身就是一个投影(而不是实现本机索引操作的东西,如数组或列表)。您可以通过首先强制第二个集合是一个列表来绕过这个问题:

    var YsAsList = Ys.ToList();
    var result = Xs.Select( (x,i) => new Point( x, YsAsList.ElementAt(i) );
    

    您必须处理的另一个问题(如果您不使用zip)是如何处理不平衡的集合。如果一个序列比另一个序列长,则必须确定正确的分辨率。您的选择是:

    1. 不支持它。失败或中止尝试。
    2. 按较短的顺序压缩尽可能多的项目。
    3. 压缩较长序列中存在的所有项目,用默认值替换短序列。

    如果你在用 Zip() ,您将自动结束第二个选项,如文档所示:

    该方法将第一个序列的每个元素与一个元素合并 第二个索引相同 序列。如果序列没有 相同数量的元素, 方法合并序列直到它 到达其中一个的结尾。为了 例如,如果一个序列有三个 元素,另一个元素有四个, 结果序列将只有 三要素。

    所有这些的最后一步是,您需要将项目结果转换为一个列表,以便将其分配给 Points 对象。那部分很容易,用 ToList() 方法:

    Points = Xs.Select( (x,i) => new Point( x, Ys.ElementAt(i) ).ToList();
    

    或在C 4中:

    Points = Xs.Zip( Ys, (a,b) => new Point(a,b) ).ToList();
    
        2
  •  1
  •   tvanfosson    14 年前

    如果两个集合的大小不同,或者其中一个或两个集合都为空,则可能是一个错误。

    public B(IEnumerable<int> Xs, IEnumerable<int> Ys) 
    { 
        if (Xs == null || Ys == null)
           throw new ArgumentNullException( "Both collections need to be non-null" );
    
        if (Xs.Count() != Ys.Count())
           throw new ArgumentException( "Collections must be of the same size" );
    
        this.Points = Xs.Zip( (x,y) => new Point { X = x, Y = y } ).ToList();
    }
    

    如果需要.NET 3.5的内容,请用替换最后一行。

    this.Points = Xs.Select( (x,i) => new Point { X = x, Y = Ys.ElementAt(i) } ).ToList();