簡體   English   中英

如何使我的 switch 語句更高效

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM