In C#, Check If The Text Contains A Keyword From The Array

Check If The Text Contains A Keyword From The Array Banner Image

Introduction

Searching for a keyword match from an array can be done by looping through each element to see if the text contains the element. This can be a costly exercise because the only way to be sure is to go through all the elements until contains returns true. So the worst-case scenerio is that a check of the entire array is done. There are a couple of ways we can write code to achieve this result.

First, we can write a method ourselves by for loop or we can use C# methods like LINQ expressions to quickly get a result. We'll look at both of these in the following examples.

Summary Table

Analysis TypeFor LoopLINQ Any
PerformanceO(N)O(N)
Lines Of Code95

Text Contains A Keyword From The Array Using For Loop Method

Below I have written a for loop that returns true if the given text contains an array element. Note that contains by default is case sensitive so if you want contains to ignore case then you StringComparison to ignore the case or put the searchKeyword to lower and array item to lower.

For Loop Method Code Example

The declared array has an array of keywords and the text has a breakfast item. This will loop through each element until one of the keywords from the array is contained in the text. If no match is found then false is returned. This is the worst-performing scenario.

string[] breakfastIdeasArray = new string[3] { "Overnight oats", "Greek yogurt", "toast" };//Declare array with values
string text = "Avocado toast";//text to be checked by string array
bool contains = SearchArrayForKeyword(text, breakfastIdeasArray);//Search by string array using contains
Console.WriteLine($"contains:{contains}");
bool SearchArrayForKeyword(string text, string[] breakfastIdeasArray)
{
    for (int i = 0; i < breakfastIdeasArray.Length; i++)//Loop through all the elements until a match on contains is found or else return false
    {
        if (text.Contains(breakfastIdeasArray[i]))//Check if the text contains a keyword from the array
        {
            return true;//Break the loop by returning true. A match is found.
        }
    }
    return false;//No keyword from array is found with contains so return false
}
Code Output
contains:True

Text Contains A Keyword From The Array Using LINQ Any

LINQ expressions provide a compact form to search go through the array and check if the text contains any keywords. The expression itself is on one nice line. The expression is fairly readable with any match from the array will break the loop.

LINQ Any Method Code Example

The bulk of the code is similar to the for loop method except there is no loop at all in this case. It is all contained in the LINQ expression. LINQ Any will return true or false if a keyword in the array is found in the text.

string[] keyWordsArray = new string[3] { "banana toast", "burrito", "Egg muffins" };//Declare array with values
string text = "Breakfast burrito";//keyword to search with contains
bool contains = SearchArrayForKeyword(text, keyWordsArray);//Search by keyword using contains
Console.WriteLine($"contains:{contains}");

bool SearchArrayForKeyword(string text, string[] keyWordsArray)
{
    if (keyWordsArray.Any(text.Contains))//Check if the text contains a keyword from the array By LINQ Any
    {
        return true;//Match on contains found return true
    }
    return false;//No element match found with contains so return false
}
Code Output
contains:True

Performance Test

I want to do a performance test. This will test the worst-case scenario of looping through the entire array without finding a match. I will do this test for both methods to see which is better. For this test, I will take an average of 10 tests. Each test will have 100 loops of the test method. Each test method will have 5 million objects go through.

Test Parameters
Test ParametersTotal
Tests10
Function Calls Per Test100
Objects Per Function Call5 Million

For Loop Speed Test Code

void TestMethod(string[] array)
{
    for (int i = 0; i < array.Length; i++)//Loop through all the elements until a match on contains is found or else return false
    {
        if (text.Contains(array[i]))//Check if the text contains a keyword from the array
        {
            return;//Break the loop. A match is found.
        }
    }
}

LINQ Any Speed Test Code

void TestMethod(string[] array)
{
    if (array.Any(text.Contains))//Check if the text contains a keyword from the array By LINQ Any
    {
        return;//Match on contains found return
    }
}
For Loop Code Output
Test 1:Function Calls:100, In 0m 3s 879ms
Test 2:Function Calls:100, In 0m 3s 958ms
Test 3:Function Calls:100, In 0m 4s 162ms
Test 4:Function Calls:100, In 0m 4s 3ms
Test 5:Function Calls:100, In 0m 3s 970ms
Test 6:Function Calls:100, In 0m 3s 924ms
Test 7:Function Calls:100, In 0m 3s 836ms
Test 8:Function Calls:100, In 0m 3s 967ms
Test 9:Function Calls:100, In 0m 3s 918ms
Test 10:Function Calls:100, In 0m 3s 995ms
For Loop Method Average Speed:3962ms, In 10 Tests
LINQ Any Code Output
Test 1:Function Calls:100, In 0m 4s 174ms
Test 2:Function Calls:100, In 0m 4s 196ms
Test 3:Function Calls:100, In 0m 4s 45ms
Test 4:Function Calls:100, In 0m 4s 34ms
Test 5:Function Calls:100, In 0m 3s 903ms
Test 6:Function Calls:100, In 0m 3s 908ms
Test 7:Function Calls:100, In 0m 3s 944ms
Test 8:Function Calls:100, In 0m 4s 9ms
Test 9:Function Calls:100, In 0m 3s 903ms
Test 10:Function Calls:100, In 0m 3s 910ms
LINQ Any Method Average Speed:4003ms, In 10 Tests
Full For Loop Test Code
Full LINQ Any Test Code

using System.Diagnostics;

int numberOfTests = 10;//Number of tests 
int numberOfFunctionCalls = 100;//Number of function calls made per test
int numberOfObjectsToCreate = 5000000;//Number test objects
int lengthOfRandomString = 50;
string testName = "LINQ Any Method";//Test name to print to average
string text = "random text!";
void TestMethod(string[] array)
{
    if (array.Any(text.Contains))//Check if the text contains a keyword from the array By LINQ Any
    {
        return;//Match on contains found return
    }
}

List<double> testSpeedList = new List<double>();
for (int testIndex = 0; testIndex < numberOfTests; testIndex++)
{
    testSpeedList.Add(StartTest(testIndex));
}
Console.WriteLine($"{testName} Average Speed:{Math.Round(testSpeedList.Average())}ms, In {numberOfTests} Tests");

double StartTest(int testIndex)
{
    Stopwatch stopwatch = new Stopwatch();
    string[] testData = GetArrayData();//Get intial random generated data
    for (int i = 0; i < numberOfFunctionCalls; i++)
    {
        stopwatch.Start();//Start the Stopwatch timer
        TestMethod(testData);//
        stopwatch.Stop();//Stop the Stopwatch timer
    }
    stopwatch.Stop();//Stop the Stopwatch timer
    Console.WriteLine($"Test {testIndex + 1}:Function Calls:{numberOfFunctionCalls}, In {stopwatch.Elapsed.Minutes}m {stopwatch.Elapsed.Seconds}s {stopwatch.Elapsed.Milliseconds}ms");
    return stopwatch.Elapsed.TotalMilliseconds;
}

string[] GetArrayData()
{
    string[] testData = new string[numberOfObjectsToCreate];
    for (int i = 0; i < numberOfObjectsToCreate; i++)
    {
        string key = GenerateRandomString(lengthOfRandomString);

        string value = GenerateRandomString(lengthOfRandomString);
        testData[i] = value;

    }
    return testData;
}


string GenerateRandomString(int length)
{
    Random random = new Random();
    const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    return new string(Enumerable.Repeat(chars, length)
      .Select(s => s[random.Next(s.Length)]).ToArray());
}

Conclusion

Overall RankMethodSpeed
1LINQ Any4003ms
2For Loop3962ms

The for loop method barely edges out the LINQ Any in performance. The difference is small enough that they are practically the same. But LINQ Any is in such a compact form that it would be more productive to use this over than writing our own for loop. Of course, you can use what you are more comfortable with and what suits your needs more.

Know any other ways to check the text contains a keyword from an array? Let me know in the comments below.

Get Latest Updates