sensei
sensei

Reputation: 7582

List within a List - How to put new line with LinQ after List within List is over?

I have a List inside List. As you can see from my foreach example, I go through flights first, and then through SEGMENTS, I print all segments from 1 flight in 1 line, only then I put NewLine for new flight, which can consist from 1 segment, or more segments. 1 Segment consist of departure time and arrival time.

When I use foreach I can put new line after each segment is finished, like this:

foreach (var flight in f)
{
    foreach (var flight1 in flight.Segments.Where(x=>x.DepartureDate > DateTime.Now))
    {
        Console.Write(
            "Departure: {0}, Arrival: {1}; ",
             flight1.DepartureDate,
             flight1.ArrivalDate);
    }
    Console.WriteLine(Environment.NewLine);
}

Result:

Departure: 2.9.2013 12:23:05, Arrival: 2.9.2013 2:23:05;

Departure: 2.9.2013 12:23:05, Arrival: 2.9.2013 2:23:05; Departure: 2.9.2013 3:2 3:05, Arrival: 2.9.2013 5:23:05;

This works nice. I am now interested how could I make this with Linq? I have my results with Linq, but all results are in one line, don't know where to put "NewLine" to put each flight segment into new line instead of all segments in one line... If I use Environment.NewLine, it will put each segment in new line. But segments from 1 flights should be in 1 line.

I use this Linq method:

public IEnumerable<Segment> GetActiveFlights(IEnumerable<Flight> flights)
{
    var query = from flight in flights
    from segment in flight.Segments
    where segment.DepartureDate > DateTime.Now
    select new Segment()
    {
        DepartureDate = segment.DepartureDate,
        ArrivalDate = segment.ArrivalDate
    };
    return query;
}

I use this to iterate then:

IEnumerable<Flight> f = flightList.GetFlights();

foreach (var flight in flightFilter.GetActiveFlights(f))
{
    Console.Write(
        "Departure: {0}, Arrival: {1}; ",
        flight.DepartureDate,
        flight.ArrivalDate);
}

Result:

Departure: 2.9.2013 12:23:05, Arrival: 2.9.2013 2:23:05; Departure: 2.9.2013 12: 23:05, Arrival: 2.9.2013 2:23:05; Departure: 2.9.2013 3:23:05, Arrival: 2.9.2013 5:23:05; Departure: 2.9.2013 12:23:05, Arrival: 1.9.2013 6:23:05; Departure: 2. 9.2013 12:23:05, Arrival: 2.9.2013 2:23:05; Departure: 2.9.2013 5:23:05, Arrival

But here all my results are in one line. How can I make that each flight(which consist of multiple segments or 1) is written in new line.

Upvotes: 0

Views: 1605

Answers (2)

King King
King King

Reputation: 63357

var query = flights.SelectMany(f=>
                   new []{ string.Join("", f.Segments
                                 .Where(s=>s.DepartureDate > DateTime.Now)
                                 .Select(s=>
                                   string.Format("Departure: {0}, Arrival: {1}; ", s.DepartureDate, s.ArrivalDate))), Environment.NewLine});
foreach(var e in query)
  Console.Write(e);

Upvotes: 0

Zev Spitz
Zev Spitz

Reputation: 15357

Console.Write(
    String.Join(Environment.NewLine, f.Select(flight => {
        var segments = flight.Segments.Where(x => x.DepartureDate > DateTime.Now);
        return String.Join("  ", segments.Select(segment => {
            return String.Format("Departure: {0}, Arrival: {1};", segment.DepartureDate, segment.ArrivalDate));
        });
    });
);

I personally prefer to have a Joined extension method on IEnumerable<T> which wraps String.Join (taking a delimiter and an optional transformation delegate), and a Formatted extension method on String which wraps String.Format:

var output = 
    f.Joined(Environment.NewLine, flight => 
        flight.Segments
              .Where(s => s.DepartureDate > DateTime.Now)
              .Joined("  ", s => "Departure: {0}, Arrival: {1};".Formatted(s.DepartureDate, s.ArrivalDate))
    );

Console.Write(output);

Upvotes: 3

Related Questions