What is the fastest way to search through a large array of strings?


I’m trying to check if a string contains a word that is similar in definition to a vehicle. For example, “plane”, “boat”, “car”, etc. There are a lot of different words that could count as vehicles, so I was wondering what it the fastest method for iterating through a list of strings? Also, if I want the list of strings to be really large, what would be the best method of populating the list?

Made a function for you

header file (StringFunctionLibrary.h)

#pragma once

#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "StringFunctionLibrary.generated.h"

/**
 * 
 */

UENUM(BlueprintType)
enum class E_Mode : uint8 {
	AND = 0 UMETA(DisplayName = "And"),
	OR = 1  UMETA(DisplayName = "Or"),
};


UCLASS()
class YOURGAME_API UStringFunctionLibrary : public UBlueprintFunctionLibrary
{
	GENERATED_BODY()
public:

		UFUNCTION(BlueprintCallable)
		static bool ContainsStringArray(const FString& SearchIn, const TArray<FString>& SubstringArray, bool bUseCase, bool bSearchFromEnd, int32 StartPosition, E_Mode mode);

};

Cpp (StringFunctionLibrary.cpp)

#include "StringFunctionLibrary.h"

bool UStringFunctionLibrary::ContainsStringArray(const FString& SearchIn, const TArray<FString>& SubstringArray, bool bUseCase, bool bSearchFromEnd, int32 StartPosition, E_Mode mode)
{
	ESearchCase::Type Case = bUseCase ? ESearchCase::CaseSensitive : ESearchCase::IgnoreCase;
	ESearchDir::Type Dir = bSearchFromEnd ? ESearchDir::FromEnd : ESearchDir::FromStart;
	int32 numFound = 0;
	bool contains = false;
	for (int32 i = 0; i < SubstringArray.Num(); i++) {

		if (mode == E_Mode::AND && SearchIn.Find(SubstringArray[i], Case, Dir, StartPosition) != -1) {
			numFound++;
		}
		else if (SearchIn.Find(SubstringArray[i], Case, Dir, StartPosition) != -1) {
				contains = true;			
		}				
	}

	if (mode == E_Mode::AND) {
		if (numFound == SubstringArray.Num())
			contains = true; else contains = false;
	}

	return contains;
}

It has a version for AND and OR comparison.
Uses the same comparison functions unreal uses under the hood just in a loop in c++ with some extra steps for the newer enum.

Replace YOURGAME_API with the API your game generates with a new c++ class.

Wow, thanks! I actually don’t know C++ though. I’m pretty new to Unreal in general. Could you walk me through how to add this to my project? Also, is there a way to return the index of the substring that was found rather than a boolean?

here is an updated version that will return a bool and and an array of found sub-strings in the order they were found (0 will be the first)

header

#pragma once

#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "StringFunctionLibrary.generated.h"

/**
 * 
 */

UENUM(BlueprintType)
enum class E_Mode : uint8 {
	AND = 0 UMETA(DisplayName = "And"),
	OR = 1  UMETA(DisplayName = "Or"),
};


UCLASS()
class YOUR_API UStringFunctionLibrary : public UBlueprintFunctionLibrary
{
	GENERATED_BODY()
public:

		UFUNCTION(BlueprintCallable)
		static void ContainsStringArray(const FString& SearchIn, const TArray<FString>& SubstringArray, bool bUseCase, bool bSearchFromEnd, int32 StartPosition, E_Mode mode, bool& contains, TArray<FString>& found);

};

CPP

// Fill out your copyright notice in the Description page of Project Settings.


#include "StringFunctionLibrary.h"

void UStringFunctionLibrary::ContainsStringArray(const FString& SearchIn, const TArray<FString>& SubstringArray, bool bUseCase, bool bSearchFromEnd, int32 StartPosition, E_Mode mode,bool &contains, TArray<FString> &found)
{
	found.Empty();
	ESearchCase::Type Case = bUseCase ? ESearchCase::CaseSensitive : ESearchCase::IgnoreCase;
	ESearchDir::Type Dir = bSearchFromEnd ? ESearchDir::FromEnd : ESearchDir::FromStart;
	int32 numFound = 0;
	
	contains = false;
	for (int32 i = 0; i < SubstringArray.Num(); i++) {

		if (mode == E_Mode::AND && SearchIn.Find(SubstringArray[i], Case, Dir, StartPosition) != -1) {
			numFound++;
		}
		else if (SearchIn.Find(SubstringArray[i], Case, Dir, StartPosition) != -1) {
				contains = true;	
				found.Add(SubstringArray[i]);
		}				
	}

	if (mode == E_Mode::AND) {
		if (numFound == SubstringArray.Num())
			contains = true; else contains = false;
			found = SubstringArray;
	}

			
}

You will need to go into the menu and pick Tools => new c++ class.

Pick all classes
type in blueprintfunctionLibrary
it should narrow down the classes to a couple, pick the one just below object.

As the name type StringFunctionLibrary

It should generate a basic class where you can copy most of the above code into (keep your paths and api name)

here are the ones straight out of my project for comparison.
StringFunctionLibrary.cpp (1.0 KB)
StringFunctionLibrary.h (735 Bytes)

Thank you so much, this is a huge help! After thinking through my problem a bit more, I now realize that I would only want to return a substring it if it was a whole word (that way ‘racecar’ doesn’t return as ‘car’). Also, would it be possible to return the index of the substring rather than the substring itself? I’m sorry to ask for all of this, but you’ve already been really helpful so I thought I might ask for one last thing.

Plugins_StrinngLib.zip (11.1 MB)
Here is a version I converted to a plugin.
It will return both an array of found words and the index at which they were found.

Just copy the plugin folder to your project and it should work

Compiled for 5.1