我正在使用纽约市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)
}
答案 0 :(得分: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,
};
请注意,此查询中没有orderby
,我们将返回匿名类型。对于要运行的“做东西(不费时)”代码,您可能需要添加更多属性。
同样的方法适用于Trips
&amp; 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,
};
由于您每次查找都会获得一条记录,因此使用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)
}
如果有帮助,请告诉我。
答案 1 :(得分:1)
我会从Trips中创建Dictionary<int, Trip>
,其中密钥为trip_id
,而Dictionary<int, Route
&gt;来自Routes
,密钥为route_id
。您的代码会针对过滤的Trips
中的每个项目,对IEnumerable<StopTime>
中的19092项进行一次迭代。同意Routes
,但至少只有27项。
编辑:
实际上更仔细地查看它,第一个字典将是Dictionary<int, int>
,其中值为route_id
。鉴于trip_id
和route_id
之间的一对一关系,您只需构建一个Dictionary<trip_id, Route>
并进行一次查找。
答案 2 :(得分:-1)
有助于理解延迟查询执行,因此您可以根据具体情况决定如何优化运行时。这是一篇很好的博客文章,可以帮助您入门:http://ox.no/posts/linq-vs-loop-a-performance-test