UE4 TArray & Iteration & Sorting

TArray<int32> IntArray;
IntArray.Init(10, 5);
TArray<FString> StrArr;
StrArr.Add    (TEXT("Hello"));
StrArr.Emplace(TEXT("World"));
// StrArr == ["Hello","World"]
Add
Emplace这里效果一样    Emplace效率更高,减少中间临时变量

FString Arr[] = { TEXT("of"), TEXT("Tomorrow") };
StrArr.Append(Arr, ARRAY_COUNT(Arr));
// StrArr == ["Hello","World","of","Tomorrow"]

 

StrArr.AddUnique(TEXT("!"));
// StrArr == ["Hello","World","of","Tomorrow","!"]

StrArr.AddUnique(TEXT("!"));
// StrArr is unchanged as "!" is already an element

 

StrArr.Insert(TEXT("Brave"), 1);
// StrArr == ["Hello","Brave","World","of","Tomorrow","!"]
SetNum可以数组扩容,超出个数补空      
StrArr.SetNum(8);
// StrArr == ["Hello","Brave","World","of","Tomorrow","!","",""]
也可以减容,达到删除元素目的
StrArr.SetNum(6);
// StrArr == ["Hello","Brave","World","of","Tomorrow","!"]

Iteration

There are several ways to iterate over the elements of your array, but the recommended way is to use C++'s ranged-for feature:

FString JoinedStr;
for (auto& Str : StrArr)
{
    JoinedStr += Str;
    JoinedStr += TEXT(" ");
}
// JoinedStr == "Hello Brave World of Tomorrow ! "

Regular index-based iteration is also possible of course:

for (int32 Index = 0; Index != StrArr.Num(); ++Index)
{
    JoinedStr += StrArr[Index];
    JoinedStr += TEXT(" ");
}

Finally, arrays also have their own iterator type for more control over your iteration. There are two methods called CreateIterator and CreateConstIterator which can be used for read-write or read-only access to the elements respectively:

for (auto It = StrArr.CreateConstIterator(); It; ++It)
{
    JoinedStr += *It;
    JoinedStr += TEXT(" ");
}

Sorting

Arrays can be sorted simply by calling the Sort method:

StrArr.Sort();
// StrArr == ["!","Brave","Hello","of","Tomorrow","World"]

 

StrArr.Sort([](const FString& A, const FString& B) {
    return A.Len() < B.Len();
});
// StrArr == ["!","of","Hello","Brave","World","Tomorrow"]

 

 

Test:

数组 合并&排序

TArray<FString> StrArr;
    StrArr.Add    (TEXT("Hello"));
    StrArr.Emplace(TEXT("World"));
    
    FString a[] = {TEXT("b"), TEXT("a"), TEXT("d"), TEXT("c")};
    StrArr.Append(a, ARRAY_COUNT(a));
    StrArr.Sort([](const FString& A, const FString& B) {
        return A.Len() > B.Len();
    });

遍历数组元素并打印到屏幕上

for (auto It = StrArr.CreateConstIterator(); It; ++ It)
{
  GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("Array test1 :%s"), **It));
}

 

FString JoinedStr;
for (auto& Str : StrArr)
{
    JoinedStr += Str;
    JoinedStr += TEXT(" ");
}
UE_LOG(YourLog, Warning, TEXT("Array test2 :%s"), *JoinedStr);

 

        for (int32 Index = 0; Index != StrArr.Num(); ++Index)
        {
            UE_LOG(YourLog, Warning, TEXT("Array test3 :%s"), *(StrArr[Index]));
        }

 

Exchange
交换数组元素
Exchange(FlavorArr2[0], FlavorArr2[1]);

 

 

Queries

1 得到数组元素数量   Num

int32 Count = StrArr.Num();

2 C-style API获得指向数组首元素地址的指针

FString* StrPtr = StrArr.GetData();
// StrPtr[0] == "!"
// StrPtr[1] == "of"
// ...
// StrPtr[5] == "Tomorrow"
// StrPtr[6] - undefined behavior

3 得到数组元素类型大小

uint32 ElementSize = StrArr.GetTypeSize();
// ElementSize == sizeof(FString)

4 获取元素 数组下标

FString Elem1 = StrArr[1];
// Elem1 == "of"

5 判断下标是否有效

bool bValidM1 = StrArr.IsValidIndex(-1);
bool bValid0  = StrArr.IsValidIndex(0);
bool bValid5  = StrArr.IsValidIndex(5);
bool bValid6  = StrArr.IsValidIndex(6);
// bValidM1 == false
// bValid0  == true
// bValid5  == true
// bValid6  == false

6 operator[] returns a reference, so it can also be used to mutate the elements inside the array, assuming your array isn't const:

StrArr[3] = StrArr[3].ToUpper();
// StrArr == ["!","of","Brave","HELLO","World","Tomorrow"]

7 获取最后元素   Last & Top    Last 和 Top (不带参数) 相同   Last() == Last(0) == Top()     Last(1) 获得倒数第二个元素

FString ElemEnd  = StrArr.Last();
FString ElemEnd0 = StrArr.Last(0);
FString ElemEnd1 = StrArr.Last(1);
FString ElemTop  = StrArr.Top();
// ElemEnd  == "Tomorrow"
// ElemEnd0 == "Tomorrow"
// ElemEnd1 == "World"
// ElemTop  == "Tomorrow"

8 是否包含  Contains & ContainsByPredicate

bool bHello   = StrArr.Contains(TEXT("Hello"));
bool bGoodbye = StrArr.Contains(TEXT("Goodbye"));
// bHello   == true
// bGoodbye == false
bool bLen5 = StrArr.ContainsByPredicate([](const FString& Str){
    return Str.Len() == 5;
});
bool bLen6 = StrArr.ContainsByPredicate([](const FString& Str){
    return Str.Len() == 6;
});
// bLen5 == true
// bLen6 == false

9 Find & FindLast 

int32 Index;
if (StrArr.Find(TEXT("Hello"), Index))
{
    // Index == 3
}
int32 IndexLast;
if (StrArr.FindLast(TEXT("Hello"), IndexLast))
{
    // IndexLast == 3, because there aren't any duplicates
}

如果不传第二个参数,则返回值为待查元素的index,如果该元素不存在,则返回INDEX_NONE

int32 Index2     = StrArr.Find(TEXT("Hello"));
int32 IndexLast2 = StrArr.FindLast(TEXT("Hello"));
int32 IndexNone  = StrArr.Find(TEXT("None"));
// Index2     == 3
// IndexLast2 == 3
// IndexNone  == INDEX_NONE
int32 Index = StrArr.IndexOfByKey(TEXT("Hello"));
// Index == 3

 

 10 IndexOfByKey & IndexOfByPredicate

int32 Index = StrArr.IndexOfByPredicate([](const FString& Str){
    return Str.Contains(TEXT("r"));
});
// Index == 2

11 FindByKey:Instead of returning indices, we can get pointers back to the found elements instead. FindByKey works like IndexOfByKey by comparing the elements to an arbitrary object, but returns a pointer to the found element. nullptr is returned if none was found:

auto* OfPtr  = StrArr.FindByKey(TEXT("of")));
auto* ThePtr = StrArr.FindByKey(TEXT("the")));
// OfPtr  == &StrArr[1]
// ThePtr == nullptr

12 FindByPredicate : Likewise, FindByPredicate can be used like IndexOfByPredicate, except a pointer is returned instead of an index:

auto* Len5Ptr = StrArr.FindByPredicate([](const FString& Str){
    return Str.Len() == 5;
});
auto* Len6Ptr = StrArr.FindByPredicate([](const FString& Str){
    return Str.Len() == 6;
});
// Len5Ptr == &StrArr[2]
// Len6Ptr == nullptr

13 FilterByPredicate:返回过滤数组

auto Filter = StrArray.FilterByPredicate([](const FString& Str){
    return !Str.IsEmpty() && Str[0] < TEXT('M');
});

Removal

Remove中字符串判断是否相同不区分大小写

StrArr.Remove(TEXT("hello"));
// StrArr == ["!","of","Brave","World","Tomorrow"]

StrArr.Remove(TEXT("goodbye"));
// StrArr is unchanged, as it doesn't contain "goodbye"

Note that "HELLO" was removed even though we asked it to remove "hello". Equality is tested via the element type's operator==; remember for FString, this is a case-insensitive comparison.

The final element of an array can be removed by the Pop method:

移除最后一个

StrArr.Pop();

Remove可以移除所有相同元素

TArray<int32> ValArr;
int32 Temp[] = { 10, 20, 30, 5, 10, 15, 20, 25, 30 };
ValArr.Append(Temp, ARRAY_COUNT(Temp));
// ValArr == [10,20,30,5,10,15,20,25,30]

ValArr.Remove(20);
// ValArr == [10,30,5,10,15,25,30]

如果只想移除第一个相同的元素

ValArr.RemoveSingle(30);
// ValArr == [10,5,10,15,25,30]

移除某位置元素

ValArr.RemoveAt(2); // Removes the element at index 2
// ValArr == [10,5,15,25,30]

ValArr.RemoveAt(99); // This will cause a runtime error as
                       // there is no element at index 99

带条件的移除

ValArr.RemoveAll([](int32 Val) {
    return Val % 3 == 0;
});
// ValArr == [10,5,25]

更有效率的删除,删除后剩余元素不能保证在原位置

TArray<int32> ValArr2;
for (int32 i = 0; i != 10; ++i)
    ValArr2.Add(i % 5);
// ValArr2 == [0,1,2,3,4,0,1,2,3,4]

ValArr2.RemoveSwap(2);
// ValArr2 == [0,1,4,3,4,0,1,3]

ValArr2.RemoveAtSwap(1);
// ValArr2 == [0,3,4,3,4,0,1]

ValArr2.RemoveAllSwap([](int32 Val) {
    return Val % 3 == 0;
});
// ValArr2 == [1,4,4]

清空

ValArr2.Empty();
// ValArr2 == []

Operators

数组数据是基础数据 数字 字符串等 数组赋值给另一个数组变量,深复制,两个数组是独立的

TArray<int32> ValArr3;
ValArr3.Add(1);
ValArr3.Add(2);
ValArr3.Add(3);

auto ValArr4 = ValArr3;
// ValArr4 == [1,2,3];
ValArr4[0] = 5;
// ValArr3 == [1,2,3];
// ValArr4 == [5,2,3];

数组可以使用+操作符合并

ValArr4 += ValArr3;
// ValArr4 == [5,2,3,1,2,3]

MoveTemp 转移数组

ValArr3 = MoveTemp(ValArr4);
// ValArr3 == [5,2,3,1,2,3]
// ValArr4 == []

== 和 !=   可以比较数组,当且仅当数组元素数量相同    顺序相同的时候两个数组 == 比较才为true

TArray<FString> FlavorArr1;
FlavorArr1.Emplace(TEXT("Chocolate"));
FlavorArr1.Emplace(TEXT("Vanilla"));
// FlavorArr1 == ["Chocolate","Vanilla"]

auto FlavorArr2 = Str1Array;
// FlavorArr2 == ["Chocolate","Vanilla"]

bool bComparison1 = FlavorArr1 == FlavorArr2;
// bComparison1 == true

for (auto& Str : FlavorArr2)
{
    Str = Str.ToUpper();
}
// FlavorArr2 == ["CHOCOLATE","VANILLA"]

bool bComparison2 = FlavorArr1 == FlavorArr2;
// bComparison2 == true, because FString comparison ignores case

Exchange(FlavorArr2[0], FlavorArr2[1]);
// FlavorArr2 == ["VANILLA","CHOCOLATE"]

bool bComparison3 = FlavorArr1 == FlavorArr2;
// bComparison3 == false, because the order has changed

 

Heap 数组可以转换成Heap 二叉树

TArray<int32> HeapArr;
for (int32 Val = 10; Val != 0; --Val)
    HeapArr.Add(Val);
// HeapArr == [10,9,8,7,6,5,4,3,2,1]
HeapArr.Heapify();
// HeapArr == [1,2,4,3,6,5,8,10,7,9]
HeapArr.HeapPush(4);
// HeapArr == [1,2,4,3,4,5,8,10,7,9,6]
eapArr.HeapRemoveAt(1);
// HeapArr == [2,4,4,6,9,5,8,10,7]

HeapPop(可带参数) == HeapPopDiscard(不带参数)

int32 TopNode;
HeapArr.HeapPop(TopNode);
// TopNode == 1
// HeapArr == [2,3,4,6,4,5,8,10,7,9]
int32 Top = HeapArr.HeapTop();
// Top == 2

Slack

数组是可变的,为避免每增加一个元素就要给数组重新分配内存,数组都有一定冗余空间,GetSlack 获取冗余个数,Num 当前数量  Max数组最大大小

TArray<int32> SlackArray;
// SlackArray.GetSlack() == 0
// SlackArray.Num()      == 0
// SlackArray.Max()      == 0

SlackArray.Add(1);
// SlackArray.GetSlack() == 3
// SlackArray.Num()      == 1
// SlackArray.Max()      == 4

SlackArray.Add(2);
SlackArray.Add(3);
SlackArray.Add(4);
SlackArray.Add(5);
// SlackArray.GetSlack() == 17
// SlackArray.Num()      == 5
// SlackArray.Max()      == 22

注意这个细节可以提高效率,当我们知道要添加元素的数量,可以重置数组

用Empty (可带一个参数,设置Max)

SlackArray.Empty();
// SlackArray.GetSlack() == 0
// SlackArray.Num()      == 0
// SlackArray.Max()      == 0
SlackArray.Empty(3);
// SlackArray.GetSlack() == 3
// SlackArray.Num()      == 0
// SlackArray.Max()      == 3
SlackArray.Add(1);
SlackArray.Add(2);
SlackArray.Add(3);
// SlackArray.GetSlack() == 0
// SlackArray.Num()      == 3
// SlackArray.Max()      == 3

相似的Reset 不清理内存,但是可以扩容

SlackArray.Reset(0);
// SlackArray.GetSlack() == 3
// SlackArray.Num()      == 0
// SlackArray.Max()      == 3
SlackArray.Reset(10);
// SlackArray.GetSlack() == 10
// SlackArray.Num()      == 0
// SlackArray.Max()      == 10

Shrink 移除冗余内存空间

SlackArray.Add(5);
SlackArray.Add(10);
SlackArray.Add(15);
SlackArray.Add(20);
// SlackArray.GetSlack() == 6
// SlackArray.Num()      == 4
// SlackArray.Max()      == 10
SlackArray.Shrink();
// SlackArray.GetSlack() == 0
// SlackArray.Num()      == 4
// SlackArray.Max()      == 4

 

Raw memory

AddUninitialized & InsertUninitialized

数组开辟一块新的内存空间

int32 SrcInts[] = { 2, 3, 5, 7 };
TArray<int32> UninitInts;
UninitInts.AddUninitialized(4);
FMemory::Memcpy(UninitInts.GetData(), SrcInts, 4*sizeof(int32));
// UninitInts == [2,3,5,7]

 

TArray<FString> UninitStrs;
UninitStrs.Emplace(TEXT("A"));
UninitStrs.Emplace(TEXT("D"));
UninitStrs.InsertUninitialized(1, 2);
new ((void*)(UninitStrs.GetData() + 1)) FString(TEXT("B"));
new ((void*)(UninitStrs.GetData() + 2)) FString(TEXT("C"));
// UninitStrs == ["A","B","C","D"]

AddZeroed & InsertZeroed (默认值初始化 0 或者空根据类型而定)

struct S
{
    S(int32 InInt, void* InPtr, float InFlt)
        : Int(InInt)
        , Ptr(InPtr)
        , Flt(InFlt)
    {
    }
    int32 Int;
    void* Ptr;
    float Flt;
};
TArray<S> SArr;
SArr.AddZeroed();
// SArr == [{ Int: 0, Ptr: nullptr, Flt: 0.0f }]

 

SetNumUninitialized & SetNumZeroed

SArr.SetNumUninitialized(3);
new ((void*)(SArr.GetData() + 1)) S(5, (void*)0x12345678, 3.14);
new ((void*)(SArr.GetData() + 2)) S(2, (void*)0x87654321, 2.72);
// SArr == [
//   { Int: 0, Ptr: nullptr,    Flt: 0.0f  },
//   { Int: 5, Ptr: 0x12345678, Flt: 3.14f },
//   { Int: 2, Ptr: 0x87654321, Flt: 2.72f }
// ]

SArr.SetNumZeroed(5);
// SArr == [
//   { Int: 0, Ptr: nullptr,    Flt: 0.0f  },
//   { Int: 5, Ptr: 0x12345678, Flt: 3.14f },
//   { Int: 2, Ptr: 0x87654321, Flt: 2.72f },
//   { Int: 0, Ptr: nullptr,    Flt: 0.0f  },
//   { Int: 0, Ptr: nullptr,    Flt: 0.0f  }
// ]

使用Uninitialized or Zeroed会有警告提醒,元素类型应该为不可变,否则会有invalid array elements and undefined错误,数组最好为固定类型,如FMatrix || FVector

Misc

不是逐元素序列化,而是整块内存二进制序列化,如果数组内容是内建类型或者扁平数据结构,可以提高数组序列化效率。

CountBytes && GetAllocatedSize 获取内存大小

Swap && SwapMemory    功能相同  except Swap does some extra error checking on the indices and will assert if the indices are out of range.

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值