1

这些天我正在学习Linq。我在 stackoverflow 或 Google 上搜索这个答案,但没有找到我需要的。

飞行等级:

public class Flight
{
    public IList<Segment> Segments { get; set; }
}

这是我的段类:

public class Segment
{
    public DateTime DepartureDate { get; set; }
    public DateTime ArrivalDate { get; set; }
}

每个航班由一个或多个航段组成。一个航段的航班是这样的:威尼斯 - 费城。有两个航段的航班是威尼斯 - 费城,费城 - 旧金山。也可以有 2 个以上的段。

我必须将 Segment2.DepartureDate 和 Segment1.ArrivalDate 之间的时间相加,以计算所有航段中到达和下一次出发之间的时间差。

我用 foreach 和这样的条件为字符串制作了这个:

public string FilterFlights(IEnumerable<Flight> flights)
{
    string s = "";
    foreach (var flight in flights)
    {
    var indexItem = 0;
    DateTime previousArrivalDateTime = new DateTime();
    TimeSpan timeSpan;

    int time = 0;
    foreach (var segments in flight.Segments)
    {
        if (indexItem == 0)
        {
        previousArrivalDateTime = segments.ArrivalDate;
        s = s + "Departure: " + segments.DepartureDate + ", Arrival: " + segments.ArrivalDate + "; ";
        }

        if (indexItem > 0)
        {
        timeSpan = segments.DepartureDate - previousArrivalDateTime;
        time += timeSpan.Hours;
        s = s + "Departure: " + segments.DepartureDate + ", Arrival: " + segments.ArrivalDate + "; ";
        previousArrivalDateTime = segments.ArrivalDate;
        }
        indexItem++;
    }
    //d = 0;

    if (time > 2)
        Console.WriteLine(s);
    }

    return s;
}

我现在想实际创建新方法而不是字符串来返回IEnumerable<Flight>,我发现使用 LinQ 是最好的。我已经在用 ElementAt 方法嗅探,但不知道我到底在做什么。

编辑: 这是我用我的 linq 方法取得的进展:

public IEnumerable<Flight> FilterFlightsWithTwoHoursPlusGap(IEnumerable<Flight> flights)
{
    int totalGap = 0;

    return from flight in flights
       //wrong where syntax, don't know how to
    where flight.Segments.Select((y, index) =>
        totalGap +=
            (index == 0)
            ? totalGap = 0
            : (y.DepartureDate - flight.Segments.ElementAt(index - 1).ArrivalDate).Hours
        ).Where(totalGap < 2) // if gap is lower than 2 hours(calculated from timespans between departure current and arrival previous
    select flight; //return flights
}

所以任何建议都会很好。

PS:任何学习linq或电子书的好网站?

4

1 回答 1

4

询问

如果要获取TimeSpan连续 s 之间每个等待期Flight Segment的 s,可以使用以下命令:

Flight flight = ...;
IEnumerable<TimeSpan> query = flight.Segments
    .SelectPairs((a, b) => b.DepartureDate - a.ArrivalDate);

对于Flight带有 N的 a Segments,这将为您提供 N - 1TimeSpan秒。

编辑:如果您想获得 a 上所有Segments之间的总等待时间Flight,您可以像这样增加 LINQ 查询:

TimeSpan totalWaitingTime = flight.Segments
    .SelectPairs((a, b) => b.DepartureDate - a.ArrivalDate)
    .Aggregate(TimeSpan.Zero, (s, t) => s + t);

帮手

public static IEnumerable<TResult> SelectPairs(
    this IEnumerable<T> source, Func<T, T, TResult> selector)
{
    var first = true;
    var prev = default(T);
    foreach (var curr in source)
    {
        if (first)
        {
            first = false;
        }
        else
        {
            yield return selector(prev, curr);
        }
        prev = curr;
    }
}

笔记

您可能很想定义SelectPairs如下:

public static IEnumerable<TResult> SelectPairs(
    this IEnumerable<T> source, Func<T, T, TResult> selector)
{
    return Enumerable.Zip(source, source.Skip(1), selector);
}

这里的陷阱是source将被枚举两次。如果这在您的场景中是可以接受的(例如,如果source只是 a List<T>),那么就去做吧。但如果不是,那么上面更长的定义会更好。

于 2013-08-30T21:12:19.010 回答