Vahid
Vahid

Reputation: 5444

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

Upvotes: 3

Views: 2506

Answers (3)

Juan
Juan

Reputation: 3705

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

Upvotes: 1

mrogal.ski
mrogal.ski

Reputation: 5920

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.

Upvotes: 1

Rob
Rob

Reputation: 27357

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

Upvotes: 6

Related Questions