How do I iterate through a UDataTable?

I’m using Driving Gameplay with Data from Excel - Unreal Engine as a guideline to set up a CSV with a bunch of common names so I can randomly generate character names at need. The CSV imports cleanly, and I have some UDataTable* nameTable correctly pointing at the CSV, where each row is stored a custom struct:


USTRUCT(Blueprintable)
struct FNameLookupTable : public FTableRowBase {
	GENERATED_BODY()
		UPROPERTY(BlueprintReadOnly, Category = "Name")
		FString nameString;
};

The guide I linked suggests using UDataTable::FindRow() to access specific rows, but I don’t want any specific row, I’d just like to grab a random name by iterating through the entire CSV, adding each struct to some TArray<FNameLookupTable> myNameStructs, then selecting a string from a random member of my array.

Is there a clean way to do this? As an alternative I could use a const to hardcode the length of my table and do something like UDataTable->FindRow(FMath::RandRange(0,lastRow), but that seems clunky and inelegant.

Hi, UDataTable has the function you need TArray<FName> GetRowNames() const, you should be able to do what you want with this. There is also UDataTableFunctionLibrary is you need BlueprintCallable functions.

Is there a way to use GetRowNames for any other row in the table, though? My table has two rows, one for the row ID, and one with the fstring data, kinda like this:


         stringFirstName
1        Bob
2        Joe
3        Larry



And so forth. GetRowNames compiles and iterates, but it returns an array of my row IDs, not of the actual FString names.

Yeah of course. So every row inside the DataTable is a struct, to get this struct you use the function FindRow(FName). To get the name you use GetRowNames(). FindRow() returns a pointer to your struct.


TArray<FTowerAbilities> AAmnesiaTower::GetAvailableAbilities()
{
	TArray<FTowerAbilities> AbilityArray;
	FString ContextString;
	TArray<FName> RowNames;
	RowNames = UpgradesSheet->GetRowNames();

	for ( auto& name : RowNames )
	{
		FTowerAbilities* row = UpgradesSheet->FindRow<FTowerAbilities>(name, ContextString);
		if ( row )
		{
			AbilityArray.Add(*row);
		}
	}
	return AbilityArray;
}

2 Likes

Oooh that fixes it, thank you for the clarification!! The example code really helped :slight_smile:

If you just need to iterate over whole UDataTable, there is a simpler way:


UDataTable* DataTable;
for(auto it : DataTable->RowMap)
{
    // it.Key has the key from first column of the CSV file
    // it.Value has a pointer to a struct of data. You can safely cast it to your actual type, e.g FMyStruct* data = (FMyStruct*)(it.Value);
}


4 Likes

Well, can you please help … I import csv file,to engine. Make a new C++ class from DataTable , include in .h file of my another class and declare variable of it.
How can I iterate through the values thou? …


pragma once

#include "CoreMinimal.h"
#include "Engine/DataTable.h"
#include "FItemInformation.generated.h"

/**
*
*/

USTRUCT(BlueprintType)
struct FItemInformation : public FTableRowBase
{
GENERATED_USTRUCT_BODY()

public:
FItemInformation() {

}

UPROPERTY(EditAnywhere)
FText itemNumber;
UPROPERTY(EditAnywhere)
FText xpos;
UPROPERTY(EditAnywhere)
FText ypos;
UPROPERTY(EditAnywhere)
FText zpos;
UPROPERTY(EditAnywhere)
FText xrot;
UPROPERTY(EditAnywhere)
FText yrot;
UPROPERTY(EditAnywhere)
FText zrot;
UPROPERTY(EditAnywhere)
FText itemType;
UPROPERTY(EditAnywhere)
FText option01;
UPROPERTY(EditAnywhere)
FText option02;
UPROPERTY(EditAnywhere)
FText option03;

};

UCLASS()
class NETWORKDIRECT_API UFItemInformation : public UDataTable
{
GENERATED_BODY()

UPROPERTY(EditAnywhere)
FItemInformation ItemInformation;

void test();

};


another class .h


FItemInformation* ItemData;

another class .cpp


if (ItemData != nullptr) {

for (auto it : ItemData)
{
////// ????
}
}

Also, not sure how to implement the test() function. Seems not comes up from suffix “.” or"->" either …

Hey @emperor_katax ,

Feel free to just start your own when you have a question in the future, rather than bumping a 2 year old thread.

To answer you’re question, give this a shot:



for(auto it : ItemData->RowData)
{
    // As noted above, it.Key will get you the name of your column, it.Value will be a pointer to whatever data you are storing.
}


2 Likes

… many many thanks for your respond. It`s been 6 hrs I’m struggling with this. well, not sure why your solution doesn’t work. Here is my question (as you advised), just post it now. Please check if you have time…

For future reference to anyone who comes across this thread like I did. As of 4.21 you can no longer access RowMap directly, it’s been protected, instead use GetRowMap()


UDataTable* DataTable;
for(auto it : DataTable->GetRowMap())

2 Likes

Just the perfect answer thanks a lot.

1 Like

If you are simply iterating trough all rows, I believe the following code is simpler and faster:

UDataTable *DataTable;
struct FMyStruct : public FTableRowBase
{
UPROPERTY()… etc
}

for (auto& data : DataTable->GetRowMap())
{
FName name = data.Key;
FMyStruct* MyStruct = reinterpret_cast<FMyStruct*>(data.Value);

// do something with name. and MyStruct->

}

Since internally it is simply a TMAP of fname and a generic pointer.
It is interesting to see that they used a uint8* instead of a void* to indicate a generic pointer.

4 Likes

finally a good answer