Find Specific Element in TArray

How can I use this in TArray ?

1 Like

hi,

i dont know what you want to do exactly but to create a TArray simply do this:

TArray< AActor* > MyActorArray;

This would give you an array which stores Actorobject-References inside. so replace AActor with some class you want to store objects of or values like int32… .

What you can do with MyActorArray is documented here: UE4-Documentation

best regards

I want to find element with specific property .

At c#

MyClass result = list.Find(x => x.Id == “xy”);

I need c++ version of this.

You want to make a Predicate to check for x.id == “xy” and pass that into FindByPredicate on your TArray.

Could you do 1 example for me? I tried it but I couldn’t do :frowning:

not having foreach like in c# i can tell you something similar if you dont want to use the functions your array provides you already.

MyClass result;

for(int i = 0; i < myArray.ArrayMax;i++)
{

//use “.” if you are using objects or "->"if you are using references

        if (myArray[i].Id == "xy")  
        {
                 result = myArray[i];
                 break;
        }

}

havnt tested that yet, but maybe it will do the magic :wink:

Given TArray< FYourType > MyArray;

FYourType* FoundEntry = MyArray.FindByPredicate([](const FYourType& InItem)
{
	return InItem.Id == "xy";
});

if(FoundEntry)
{
	// ...
}

That’s using a lambda, but the predicate can be any kind of callable type.

2 Likes

You can also use C++11 range-based-for (which is basically C# foreach) with our containers.

for(const auto& Item : MyArray)
{
    // ...
}

ABaseEffect* APlayerCharacter::GetPlayerEffectByID(int32 ID){

TArray Effects;

ABaseEffect** eff = Effects.FindByPredicate([](ABaseEffect*& InItem)
{
return InItem->ID == ID;
});

return *eff;

}

Error 4 error C3493: ‘ID’ cannot be implicitly captured because no default capture mode has been specified C:\Users\AhmetFaruk\Desktop\TenekurOffline\Source\TenekurOffline\Character\PlayerCharacter.cpp 959 1 TenekurOffline

How can I fix it ?

ah, i wasnt aware of that, thanks for that :wink:

this may help c++ - Compiler error C3493: 'func' cannot be implicitly captured because no default capture mode has been specified - Stack Overflow

You’ll need to capture the variable you want to compare against, since it’s just an int32, you can just do this via value:

ABaseEffect** eff = Effects.FindByPredicate([ID](ABaseEffect*& InItem) { return InItem->ID == ID; });

You’ll probably want to read up on lambdas in C++ if you’re planning on making use of them.

This doesn’t seem to work for TArray of UObjects or Structs in 4.14.

I am using it with UObjects*. Can you show your implementation?

You may also need to override an operator. But first show your code or at least what you want to do

Thanks for checking :slight_smile:

here is the struct definition:

USTRUCT(BlueprintType)
struct FStaffUnitDef
{
	GENERATED_USTRUCT_BODY()

public:
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
		EStaffUnitTypes UnitType = EStaffUnitTypes::SU_Combat;

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
		float StaffLimit = 25;

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
		TArray<FStaffMemberDef> StaffList;
};

The structis used in an array:

	FStaffUnitDef CombatUnit;
	FStaffUnitDef DevelopmentUnit;
	FStaffUnitDef ConstructionUnit;
	FStaffUnitDef SupportUnit;
	FStaffUnitDef IntelUnit;
	FStaffUnitDef MedicalUnit;

	FStaffUnitDef BriggUnit;
	FStaffUnitDef WaitingRoomUnit;
	FStaffUnitDef SickBayUnit;

	CombatUnit.UnitType = EStaffUnitTypes::SU_Combat;
	CombatUnit.StaffLimit = 25;
	StaffUnitList.Add(CombatUnit);

	DevelopmentUnit.UnitType = EStaffUnitTypes::SU_Development;
	DevelopmentUnit.StaffLimit = 50;
	StaffUnitList.Add(DevelopmentUnit);

	ConstructionUnit.UnitType = EStaffUnitTypes::SU_Construction;
	ConstructionUnit.StaffLimit = 25;
	StaffUnitList.Add(ConstructionUnit);

        //  ... and so on...

Here is the function that shall find a specific unit:

.h:

	UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Data")
	FStaffUnitDef* GetUnit(EStaffUnitTypes type);

.cpp:

FStaffUnitDef* UMotherbaseClass::GetUnit(EStaffUnitTypes type)
{
	return (StaffUnitList.FindByPredicate([&]( FStaffUnitDef staffunit) { return staffunit.UnitType == type; }));
}

On compile, I get the error message:

Inappropriate ‘*’ on variable of type ‘FStaffUnitDef’, cannot have an exposed pointer to this type.

So this is where I am stuck :frowning:
How can I get an item of an array that I can work with (no read only copy).
As the array struct ('FStaffUnitDef) contains an array itself, I want to be able to edit it.

Any help is appreciated :slight_smile:

Hey there,

FindByPredicate is returning a pointer-to-pointer, so you would need to dereference this one to get your object. Jamie Dale did that above on Jan 16. Here is another example:

FString Name;
TArray<AActor*> myArray;

AActor* DesiredElement = *(myArray.FindByPredicate(
		[&](AActor* Actor)
	{
		return Actor->GetName() == Name;
	}
	));

or this using a struct:

float SomeValue;
	TArray<FCharacterStat> myArray;

	FCharacterStat& DesiredElement = *(myArray.FindByPredicate(
		[&](FCharacterStat Stat)
	{
		return Stat.Value== SomeValue;
	}
	));

I changed my code, so now it compiles.

FStaffUnitDef UMotherbaseClass::GetUnit(EStaffUnitTypes type)
{
	
	FStaffUnitDef& Result = *(StaffUnitList.FindByPredicate(
		[&](FStaffUnitDef unit)
	{
		return unit.UnitType == type;
	}
	));
	return Result;
}

However, when I access the result, I somehow cannot modify it…
Only when I use the commented-out hardcoded call, a staff member is added.

void UMotherbaseClass::AddStaffMember(EStaffUnitTypes unit, FStaffMemberDef data)
{
	GetUnit(unit).StaffList.Add(data);

	//StaffUnitList[0].StaffList.Add(data);

	return;
}

What am I still doing wrong?

Your problem lies probably here:

FStaffUnitDef UMotherbaseClass::GetUnit(EStaffUnitTypes type)

Your function returns an object by value and not by reference - a typical error I often do myself ;). So returning this struct will break the reference to the object inside the list. It has the same values but the object is a different one.

What you need to do is returning a pointer or a reference to this listelement. F.e. like this:

 FStaffUnitDef* UMotherbaseClass::GetUnit(EStaffUnitTypes type)
 {
     
     FStaffUnitDef** Result = StaffUnitList.FindByPredicate(
         [&](FStaffUnitDef unit)
     {
         return unit.UnitType == type;
     }
     );
     return *Result;
 }