简体   繁体   中英

Select more than one property using Linq

Let's say we have a Line class defined by Point startPoint and Point endPoint .

If I have list of these lines, how can I extract all the points in them into one List<Point> using LINQ .

This is what I have so far:

IList<Point> points1 = lines.Select(o => o.StartPoint).ToList();
IList<Point> points2 = lines.Select(o => o.EndPoint).ToList();

IList<Point> points = points1.Concat(points2).ToList();

If you want a shorter way, you can do something like this:

var points = lines.SelectMany(l => new[] { l.StartPoint, l.EndPoint }).ToList();

However, your current code is debateably more readable, but more importantly, does not create an array for each line you iterate.

However, you don't need to invoke ToList() for each set, you can simply write:

var points = lines.Select(l => l.StartPoint).Concat(lines.Select(l => l.EndPoint)).ToList();

You can do this in a few different ways. One is to use Tuple<Point, Point> :

IEnumerable<Tuple<Point, Point>> r = lines.Select(l => new Tuple<Point, Point>(l.StartPoint, l.EndPoint));

To access these then you have to keep in mind that StartPoint would be Item1 and EndPoint will be Item2 :

foreach ( Tuple<Point, Point> se in r )
{
    var start = se.Item1;
    var end   = se.Item2;
}

Another one could be to make an array of 2 elements each :

IEnumerable<Point[]> r = lines.Select(l => new Point[2]{ l.StartPoint, l.EndPoint });

To access these you have to keep in mind that index 0 contains your StartPoint and index 1 contains your EndPoint :

foreach( Point[] parr in r )
{
    if( parr.Length == 2 )
    {
        var start = parr[0];
        var end   = parr[1];
    }
}

You can always create a flat model containing only these two properties and then just cast/create it in the Select .

There are dozens of ways to achieve what you want. The real question is what do you want to do with this result later.

Your solution is the closer you can get to it. If you don't want to enumerate twice the list you should go for a Foreach/Map approach:

var points = new List<Point>();

lines.Map(line =>
{
     points.Add(line.startPoint);
     points.Add(line.EndPoint);
 } );

If you don't want to use Concat you can use Union:

lines.Select(o => o.StartPoint).Union(lines.Select(o => o.EndPoint)).ToList();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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