UE5 C++ TSet

概念

  • TSet是一种快速容器类,用于在排序不重要的情况下存储唯一元素
  • TSet 也是值类型,支持常规复制、赋值和析构函数操作,以及其元素较强的所有权
  • TSet 被销毁时,其元素也将被销毁。键类型也必须是值类型

创建

  TSet<FString> FruitSet;

添加元素

  • Add 将提供键加入set

     FruitSet.Add(TEXT("Banana"));
     FruitSet.Add(TEXT("Grapefruit"));
     FruitSet.Add(TEXT("Pineapple"));
     // FruitSet == [ "Banana", "Grapefruit", "Pineapple" ]
    
     FruitSet.Add(TEXT("Pear"));
     FruitSet.Add(TEXT("Banana"));
     // FruitSet == [ "Banana", "Grapefruit", "Pineapple", "Pear" ]
     // Note:Only one banana entry.
    
  • 使用Emplace代替Add,避免插入集合时创建临时文件

  FruitSet.Emplace(TEXT("Orange")); // FruitSet == [ "Banana", "Grapefruit", "Pineapple", "Pear", "Orange" ]
  • Append函数来插入另一个集合中的所有元素
    Set<FString> FruitSet2;
    FruitSet2.Emplace(TEXT("Kiwi"));
    FruitSet2.Emplace(TEXT("Melon"));
    FruitSet2.Emplace(TEXT("Mango"));
    FruitSet2.Emplace(TEXT("Orange"));
    FruitSet.Append(FruitSet2);
    // FruitSet == [ "Banana", "Grapefruit", "Pineapple", "Pear", "Orange", "Kiwi", "Melon", "Mango" ]
    

迭代

  • for-range
    for (auto& Elem :FruitSet)
        {
            FPlatformMisc::LocalPrint(
                *FString::Printf(
                    TEXT(" \"%s\"\n"),
                    *Elem
                )
            );
        }
        // Output:
        //  "Banana"
        //  "Grapefruit"
        //  "Pineapple"
        //  "Pear"
        //  "Orange"
        //  "Kiwi"
        //  "Melon"
        //  "Mango"
    
  • 迭代器
    • CreateIterator 返回拥有读写访问权限的迭代器
    • CreateConstIterator 返回拥有只读访问权限的迭代器
     for (auto It = FruitSet.CreateConstIterator(); It; ++It)
        {
            FPlatformMisc::LocalPrint(
                *FString::Printf(
                    TEXT("(%s)\n"),
                    *It
                )
            );
        }
    

查询

  • Num函数可查询集合中保存的元素数量
      int32 Count = FruitSet.Num();  // Count == 8
    
  • Contains函数确定集合是否包含特定元素
 bool bHasBanana = FruitSet.Contains(TEXT("Banana"));   // bHasBanana == true
 bool bHasLemon = FruitSet.Contains(TEXT("Lemon"));  // bHasLemon == false
  • FSetElementId 结构体可查找集合中某个键的索引

    • 可使用该索引与 operator[] 查找元素
    • 在非常量集合上调用 operator[] 将返回非常量引用,而在常量集合上调用将返回常量引用
    FSetElementId BananaIndex = FruitSet.Index(TEXT("Banana"));
        // BananaIndex is a value between 0 and (FruitSet.Num() - 1)
        FPlatformMisc::LocalPrint(
            *FString::Printf(
                TEXT(" \"%s\"\n"),
                *FruitSet[BananaIndex]
            )
        );
        // Prints "Banana"
    
        FSetElementId LemonIndex = FruitSet.Index(TEXT("Lemon"));
        // LemonIndex is INDEX_NONE (-1)
        FPlatformMisc::LocalPrint(
            *FString::Printf(
                TEXT(" \"%s\"\n"),
                *FruitSet[LemonIndex]
            )
        ); // Assert!
    
  • Find 将返回指向元素数值的指针

    • 如果映射不包含该键,则返回nullptr
    • 对常量集合调用Find,返回的指针也将为常量
     FString* PtrBanana = FruitSet.Find(TEXT("Banana")); // *PtrBanana == "Banana"
     FString* PtrLemon = FruitSet.Find(TEXT("Lemon")); //  PtrLemon == nullptr
    
  • Array函数会返回一个TArray,其中填充了TSet中每个元素的一份副本

    • 被传递的数组在填入前会被清空,因此元素的生成数量将始终等于集合中的元素数量
     TArray<FString> FruitArray = FruitSet.Array();
     // FruitArray == [ "Banana","Grapefruit","Pineapple","Pear","Orange","Kiwi","Melon","Mango" ] (order may vary)
    

移除元素

  • Remove 可按索引移除元素
    • Remove 函数会返回已删除元素的数量
    • 如果给定的键未包含在集合中,则会返回0
    • 如果TSet支持重复的键,Remove将移除所有匹配元素
    FruitSet.Remove(0);  // FruitSet == [ "Grapefruit","Pineapple","Pear","Orange","Kiwi","Melon","Mango" ]
    int32 RemovedAmountPineapple = FruitSet.Remove(TEXT("Pineapple"));  // RemovedAmountPineapple == 1
    // FruitSet == [ "Grapefruit","Pear","Orange","Kiwi","Melon","Mango" ]
    FString RemovedAmountLemon = FruitSet.Remove(TEXT("Lemon")); // RemovedAmountLemon == 0
    
  • EmptyReset 函数可将集合中的所有元素移除
    • Empty 可采用参数指示集合中保留的slack量,而 Reset 则是尽可能多地留出slack量
    TSet<FString> FruitSetCopy = FruitSet;
        // FruitSetCopy == [ "Grapefruit","Pear","Orange","Kiwi","Melon","Mango" ]
    
        FruitSetCopy.Empty();
        // FruitSetCopy == []
    

排序

  • TSet可以排序。排序后,迭代集合会以排序的顺序显示元素,但下次修改集合时,排序可能会发生变化。由于排序不稳定,可能按任何顺序显示集合中支持重复键的等效元素
  • Sort 函数使用指定排序顺序的二进制谓词
 FruitSet.Sort([](const FString& A, const FString& B) {
        return A > B; // sort by reverse-alphabetical order
    });
    // FruitSet == [ "Pear", "Orange", "Melon", "Mango", "Kiwi", "Grapefruit" ] (order is temporarily guaranteed)

    FruitSet.Sort([](const FString& A, const FString& B) {
        return A.Len() < B.Len(); // sort strings by length, shortest to longest
    });
    // FruitSet == [ "Pear", "Kiwi", "Melon", "Mango", "Orange", "Grapefruit" ] (order is temporarily guaranteed)

运算符

  • TArray一样,TSet是常规值类型,可通过标准复制构造函数或赋值运算符进行复制
  • 因为集合严格拥有其元素,复制集合的操作是深层的,所以新集合将拥有其自身的元素副本
 TSet<FString> NewSet = FruitSet;
 NewSet.Add(TEXT("Apple"));
 NewSet.Remove(TEXT("Pear"));
 // FruitSet == [ "Pear", "Kiwi", "Melon", "Mango", "Orange", "Grapefruit" ]
 // NewSet == [ "Kiwi", "Melon", "Mango", "Orange", "Grapefruit", "Apple" ]

Slack

  • Slack是不包含元素的已分配内存
  • 调用 Reserve可分配内存,无需添加元素
  • 通过非零slack参数调用ResetEmpty 可移除元素,无需将其使用的内存取消分配
  • Slack优化了将新元素添加到集合的过程,因为可以使用预先分配的内存,而不必分配新内存
  • 它在移除元素时也十分实用,因为系统不需要将内存取消分配
  • 在清空希望用相同或更少的元素立即重新填充的集合时,此方法尤其有效
    FruitSet.Reset();  // FruitSet == [ <invalid>, <invalid>, <invalid>, <invalid>, <invalid>, <invalid> ]
    
     FruitSet.Reserve(10);
     for (int32 i = 0; i < 10; ++i)
      {
          FruitSet.Add(FString::Printf(TEXT("Fruit%d"), i));
      }
      // FruitSet == [ "Fruit9", "Fruit8", "Fruit7" ..."Fruit2", "Fruit1", "Fruit0" ]
    
  • Shrink 将从容器的末端移除所有slack,但这会在中间或开始处留下空白元素
     // Remove every other element from the set.
        for (int32 i = 0; i < 10; i += 2)
        {
            FruitSet.Remove(FSetElementId::FromInteger(i));
        }
        // FruitSet == ["Fruit8", <invalid>, "Fruit6", <invalid>, "Fruit4", <invalid>, "Fruit2", <invalid>, "Fruit0", <invalid> ]
    
        FruitSet.Shrink();
        // FruitSet == ["Fruit8", <invalid>, "Fruit6", <invalid>, "Fruit4", <invalid>, "Fruit2", <invalid>, "Fruit0" ]
    
    • 在上述代码中,Shrink 只删除了一个无效元素,因为末端只有一个空元素
  • 要移除所有slack,首先应调用 CompactCompactStable 函数,将空白空间组合在一起,为调用 Shrink 做好准备。
  • CompactStable 可在合并空元素时保持元素的排序
    FruitSet.CompactStable();
    // FruitSet == ["Fruit8", "Fruit6", "Fruit4", "Fruit2", "Fruit0", <invalid>, <invalid>, <invalid>, <invalid> ]
    FruitSet.Shrink();
    // FruitSet == ["Fruit8", "Fruit6", "Fruit4", "Fruit2", "Fruit0" ]
    
posted @ 2023-06-22 20:24  scyrc  阅读(108)  评论(0编辑  收藏  举报