2

ニューヨーク市の MTA 地下鉄システムの GTFS データを扱っています。特定の停留所での各ルートの停車時間を見つける必要があります。そのために、特定の stop_id について、持っている StopTimes DataTable から停止時刻を取得します。現在から次の 2 時間までの停止時間のみが必要です。

次に、trip_id 値を使用して、停車時刻ごとにルートを検索する必要があります。そのルートから、ルート名または停車時刻の番号を取得するために、route_id 値を使用してルートを検索する必要があります。

各 DataTable のカウントは次のとおりです: StopTimes(522712)、Trips(19092)、Routes(27)。

現在、この実行には 20 秒から 40 秒かかります。どうすればこれをスピードアップできますか? あらゆる提案を歓迎します。ありがとう!

foreach (var r in StopTimes.OrderBy(z => z.Field<DateTime>("departure_time").TimeOfDay)
                           .Where(z => z.Field<string>("stop_id") == stopID &&
                                  z["departure_time"].ToString() != "" &&
                                  z.Field<DateTime>("departure_time").TimeOfDay >= DateTime.UtcNow.AddHours(-5).TimeOfDay &&
                                  z.Field<DateTime>("departure_time").TimeOfDay <= DateTime.UtcNow.AddHours(-5).AddHours(2).TimeOfDay))
        {
            var trip = (from z in Trips
                        where z.Field<string>("trip_id") == r.Field<string>("trip_id") &&
                              z["route_id"].ToString() != ""
                        select z).Single();

            var route = (from z in Routes
                         where z.Field<string>("route_id") == trip.Field<string>("route_id")
                         select z).Single();

            // do stuff (not time-consuming)
        }
4

3 に答える 3

2

これを試して:

var now = DateTime.UtcNow;
var tod0 = now.AddHours(-5).TimeOfDay;
var tod1 = now.AddHours(-5).AddHours(2).TimeOfDay;

var sts =
    from st in StopTimes
    let StopID = st.Field<string>("stop_id")
    where StopID == stopID
    where st["departure_time"].ToString() != ""
    let DepartureTime = st.Field<DateTime>("departure_time").TimeOfDay
    where DepartureTime >= tod0
    where DepartureTime >= tod1
    let TripID = st.Field<string>("trip_id")
    select new
    {
        StopID,
        TripID,
        DepartureTime,
    };

このクエリには no がなくorderby、匿名型を返していることに注意してください。「処理を行う (時間がかからない)」コードを実行するには、いくつかのプロパティを追加する必要がある場合があります。

同じアプローチがTrips&にも起こりRoutesます。

var ts =
    from t in Trips
    where t["route_id"].ToString() != ""
    let TripID = t.Field<string>("trip_id")
    let RouteID = t.Field<string>("route_id")
    select new
    {
        TripID,
        RouteID,
    };

var rs =
    from r in Routes
    let RouteID = r.Field<string>("route_id")
    select new
    {
        RouteID,
    };

ルックアップごとに 1 つのレコードを取得しているので、使用ToDictionary(...)するのが適切な選択です。

var tripLookup = ts.ToDictionary(t => t.TripID);
var routeLookup = rs.ToDictionary(r => r.RouteID);

クエリは次のようになります。

var query = from StopTime in sts.ToArray()
            let Trip = tripLookup[StopTime.TripID]
            let Route = routeLookup[Trip.RouteID]
            orderby StopTime.DepartureTime
            select new
            {
                StopTime,
                Trip,
                Route,
            };

私が使用し、最後に権利を.ToArray()付けたことに注意してください。orderby

そして、次のようにコードを実行します。

foreach (var q in query)
{
    // do stuff (not time-consuming)
}

これが役立つかどうか教えてください。

于 2011-03-04T03:50:07.927 に答える
1

Dictionary<int, Trip>キーが であるfrom Trips とキーが でtrip_idあるDictionary<int, Routefromを作成しRoutesますroute_idTripsコードは、filtered 内のアイテムごとに19092 個のアイテムを 1 回反復処理していますIEnumerable<StopTime>。についても同じ取引ですRoutesが、少なくともそこには 27 個のアイテムしかありません。

編集:

実際にもっと詳しく見てみると、最初の辞書はDictionary<int, int>値がroute_id. と の間の 1 対 1 の関係を考えると、を構築して 1 回のルックアップをtrip_id実行できます。route_idDictionary<trip_id, Route>

于 2011-03-04T03:22:05.733 に答える
-1

遅延クエリの実行を理解するのに役立つため、ランタイムを最適化する方法をケースバイケースで決定できます。これは、始めるのに役立つ良いブログ投稿です: http://ox.no/posts/linq-vs-loop-a-performance-test

于 2011-03-25T23:00:16.367 に答える