[英]How can I make my switch statement more performant
我有一個用於多種類型枚舉的 switch 語句,我根據類型檢查對應於該類型的時間戳是否在提供的日期范圍內。 我使用了 10 個開關,想知道是否有性能更高的查詢功能。
是否可以使用 selectmany 或 where from linq 來提高性能?
private Event[] FilterNotifications(Event[] eventResponseItems, DateTime beginDate, DateTime endDate)
{
var eventList = eventResponseItems.ToList();
foreach (var eEvent in eventList)
{
switch (eEvent.EventType)
{
case "RouteStarted":
if (!InRange(beginDate, endDate, eEvent.EventInfo.RouteInfo.RouteTimestamps.Started))
eventList.Remove(eEvent);
break;
case "RouteDeparted":
if (!InRange(beginDate, endDate, eEvent.EventInfo.RouteInfo.RouteTimestamps.Arrived))
eventList.Remove(eEvent);
break;
case "RouteArrived":
if (!InRange(beginDate, endDate, eEvent.EventInfo.RouteInfo.RouteTimestamps.Completed))
eventList.Remove(eEvent);
break;
case "RouteCompleted":
if (!InRange(beginDate, endDate, eEvent.EventInfo.RouteInfo.RouteTimestamps.Departed))
eventList.Remove(eEvent);
break;
case "StopArrived":
if (!InRange(beginDate, endDate, eEvent.EventInfo.StopInfo.ArrivalTimeStamp))
eventList.Remove(eEvent);
break;
case "StopDeparted":
if (!InRange(beginDate, endDate, eEvent.EventInfo.StopInfo.DepartureTimeStamp))
eventList.Remove(eEvent);
break;
case "StopServicing":
if (!InRange(beginDate, endDate, eEvent.EventInfo.StopInfo.ArrivalTimeStamp))
eventList.Remove(eEvent);
break;
case "StopCancelled":
if (!InRange(beginDate, endDate, eEvent.EventInfo.StopInfo.DepartureTimeStamp))
eventList.Remove(eEvent);
break;
case "RouteStatusChanged":
if (!InRange(beginDate, endDate, eEvent.EventInfo.StopInfo.ArrivalTimeStamp))
eventList.Remove(eEvent);
break;
}
}
return eventList.ToArray();
}
private bool InRange(DateTime beginTime, DateTime endTime, string timeStamp)
{
DateTime timeStmp = DateConverter.ToInternal(timeStamp).Value;
if ( timeStmp >= beginTime)
{
if (endTime != new DateTime() && timeStmp <= endTime)
{
return true;
}
return true;
}
return false;
}
在您的方法中沒有太多可以優化性能的方法,因為它不使用任何復雜的迭代。
從可讀性的角度來看,您可以為此使用字典。 這也將允許您避免使用.Where()
完全實現返回的數組。
您將需要一個稍微復雜的Func<>
如下所示,以便將每個事件的事件信息枚舉轉換為時間戳字符串。
var RouteControl = new Dictionary<string,Func<Event,string>>()
{
{ "RouteStarted" , eEvent => eEvent.EventInfo.RouteInfo.RouteTimestamps.Started },
{ "RouteDeparted" , eEvent => eEvent.EventInfo.RouteInfo.RouteTimestamps.Arrived },
{ "RouteArrived" , eEvent => eEvent.EventInfo.RouteInfo.RouteTimestamps.Completed },
{ "RouteCompleted" , eEvent => eEvent.EventInfo.RouteInfo.RouteTimestamps.Departed },
{ "StopArrived" , eEvent => eEvent.EventInfo.StopInfo.ArrivalTimeStamp },
{ "StopDeparted" , eEvent => eEvent.EventInfo.StopInfo.DepartureTimeStamp },
{ "StopServicing" , eEvent => eEvent.EventInfo.StopInfo.ArrivalTimeStamp },
{ "StopCancelled" , eEvent => eEvent.EventInfo.StopInfo.DepartureTimeStamp },
{ "RouteStatusChanged" , eEvent => eEvent.EventInfo.StopInfo.ArrivalTimeStamp }
};
return eventResponseItems.Where(eEvent =>
!RouteControl.ContainsKey(eEvent.EventType) ||
InRange(beginDate, endDate, RouteControl[eEvent.EventType](eEvent))
).ToArray();
與性能相比,我更關心代碼的可維護性。 如果我們一開始只是試圖刪除重復的代碼,並使剩余的代碼易於理解,那么我最終會得到這樣的結果:
private Event[] FilterNotifications(Event[] eventResponseItems, DateTime beginDate, DateTime endDate)
{
return eventResponseItems
.Where(e => InRange(beginDate, endDate, GetEventRouteTimeStampFromEventType(e.EventInfo.RouteInfo.RouteTimestamps, e.EventType)))
.ToArray();
}
private string GetEventRouteTimeStampFromEventType(RouteTimeStamps routeTimeStamps, string eventType)
{
switch (eventType)
{
case "RouteStarted":
case "StopCancelled":
return routeTimestamps.Started;
case "RouteDeparted":
return routeTimestamps.Arrived;
case "RouteArrived":
return routeTimestamps.Completed;
case "RouteCompleted":
return routeTimestamps.Departed;
case "StopDeparted":
return routeTimestamps.DepartureTimeStamp;
case "RouteStatusChanged":
case "StopServicing":
case "StopArrived":
return routeTimestamps.ArrivalTimeStamp;
default: throw new ArgumentOutOfRangeException();
}
}
}
而且,事實上,這也能獲得更好的性能(因為您正在過濾,而不是創建一個列表並從中刪除項目)。 所以這是一場不錯的勝利。
請注意,我已經假設您擁有有限的事件類型列表,並且如果您看到其他任何內容(通常是選擇 switch 語句時的情況),您希望拋出異常。 如果不是這種情況,您可以執行類似返回 null 的操作,並相應地調整剩余的代碼。
List.Remove 在 O(n) 中,所以你的整個循環在 O(n^2) 中。 如果在迭代僅包含所需元素的第一個列表時填充第二個列表,則可能會提高性能。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.