Search code examples
c#arraysloopstimerstopwatch

How to keep variables in dynamic array for a limited time


I have a c# winforms application which downloads content from certain webpages and puts it in a string variable called content. It then searches for specific keywords (contained in a string, and separated by comma) within content, and sounds an alarm if there's a match; otherwise, makes another webrequest and run the search again.

My client asked for something different: He wants the program to keep running after it finds a keyword and triggers the alarm, but this time it should only look for the remaining keywords that were not found in the last 5 minutes.

I thought about adding found keywords to a dynamic array, called foundKeywordsList, and starting a stopwatch or some kind of timer to remove them from the array after 5 minutes' passed, but I don't know how to do just that, so that's my question. So far this is the relevant code (it runs inside a loop):

List<string> foundKeywordsList = new List<string>();

string keywords = "scott,mark,tom,bob,sam";

string[] keywordArray = keywords.Split(',');

foreach (string kw in keywordArray)
{
    // Performs search only if the keyword wasn't found in the last 5 minutes
    if (!foundKeywordsList.Contains(kw) && content.IndexOf(kw) != -1)
    {
        //
        // code for triggering the alarm
        //

        foundKeywordsList.Add(kw);
    }
}

Thanks everyone.


Solution

  • What would probably work better is to create a Dictionary<string, DateTime> where you add the found key word and the time that it was found. Then create a method that is called via a timer with the body:

    foundKeywordsDict = foundKeywordsDict.Where(kvp => kvp.Value > DateTime.Now.AddMinutes(-5))
                        .ToDictionary(kvp => kvp.Key, kvp = > kvp.Value)
    

    What this will do is create a new dictionary from the existing one where all the keywords have been added within the last 5 min.

    EDIT: There are two types of timers in c#, the System.Timers.Timer and the System.Threading.Timer. The following is using the later. Using the System.Threading.Timer, the Timer will create a new thread when the timer hits, calling the TimerCallback delegate that you pass in the constructor, and restart the timer. The TimerCallback only accepts methods with the signature of void MethodName(object state) (it can be static).

    For your case, you would want your code to look similar to this:

    public void RemoveOldFoundKeywords(object state)
    {
        lock(foundKeywordsDict) //since you are working with threads, you need to lock the resource
            foundKeywordsDict = foundKeywordsDict.Where(kvp => kvp.Value > DateTime.Now.AddMinutes(-5))
                        .ToDictionary(kvp => kvp.Key, kvp = > kvp.Value)
    }
    

    To create the timer, you would want something similar to this:

    Using System.Threading;
    ....
    
    int timerInterval = 60*1000 //one minute in milliseconds
    TimerCallback timerCB = new TimerCallback(RemoveOldFoundKeywords);
    
    Timer t = new Timer(
        timerCB,         //the TimerCallback delegate
        null,            //any info to pass into the called method
        0,               //amount of time to wait before starting the timer after creation
        timerInterval);  //Interval between calls in milliseconds
    

    Additional information on the System.Threading.Timer class can be found here, info for the System.Timers.Timer class can be found here and info for the lock keyword can be found here.