Skip to content

Arrays, Sets, Maps, and ForEach

Containers are how a Blueprint remembers zero, one, or many things. Most container bugs are not "Unreal being weird"; they are the graph asking for an item that is not in the container, or choosing the wrong container shape for the job.

The one-minute version

  • An Array is an ordered list of one type. It can be empty, it can contain duplicates, and its first index is 0.
  • A Set is an unordered collection of unique values of one type. It is good for "who is currently inside this trigger?" because adding the same actor twice still leaves one entry.
  • A Map stores key-value pairs. The key is how you find the value later: item ID -> item count, surface type -> footstep sound, checkpoint name -> spawn data.
  • For Each Loop runs once per element in a container snapshot. It does not make invalid object references safe, and a huge loop still costs real frame time.
  • Empty containers are normal. Branch on Length, Contains, or Find result before assuming an item exists.
  • Use containers to model the data you actually need, not as a way to avoid deciding who owns the data.

What each container stores

All three Blueprint containers are typed. An array of BP_Door references only stores BP_Door references. A map from Name to Integer only accepts those key and value types.

Container Shape Allows duplicates? Order matters? Beginner use
Array Index -> Value Yes Yes Inventory slots, ordered patrol points, trace results, all actors returned by a search.
Set Value No No stable order to rely on Current overlap members, unlocked abilities, actors already processed this pulse.
Map Key -> Value Keys no, values yes No stable order to rely on Item counts by ID, widget references by slot name, tuning values by tag/name.

Array indices are positions. Map keys are labels. Set entries are their own labels.

Array InventorySlots:
    [0] Potion
    [1] Potion
    [2] Key

Set OverlappingActors:
    BP_PlayerCharacter
    BP_AICompanion

Map ItemCounts:
    Potion -> 2
    Key    -> 1

That difference matters when a bug happens. "Index out of bounds" is an array position problem. "Find returned false" is a map key problem. "Add did not increase count" may be a set doing its job by refusing a duplicate.

Arrays

Use an array when the position in the list matters, or when you naturally want to walk through every item.

Common beginner arrays:

  • waypoints in patrol order;
  • inventory slots shown left to right;
  • actors returned by Get All Actors Of Class;
  • recent damage numbers;
  • hit results from a multi trace.

The empty array is not an error:

Get All Actors Of Class BP_Enemy
-> Out Actors = [] when no enemies exist
-> Length = 0

The dangerous part is indexing without checking:

Bad:
    Out Actors -> Get index 0 -> call AttackPlayer

Safer:
    Out Actors -> Length > 0
    true -> Get index 0
    false -> no enemy found path

Blueprint arrays are zero-based:

Length = 3
valid indices = 0, 1, 2
last valid index = Length - 1

If you get an out-of-bounds warning, do not guard it with Is Valid first. The problem is that the list does not contain an element at that index.

Sets

Use a set when uniqueness is the point and order is not.

A trigger volume that tracks actors inside it is the classic example:

On Component Begin Overlap
-> Other Actor passes filter
-> Add Other Actor to CurrentOverlappers set

On Component End Overlap
-> Remove Other Actor from CurrentOverlappers set

CanOpenDoor:
    return CurrentOverlappers contains PlayerCharacter

An array can also do this, but arrays make duplicates your problem. If two components on the same actor overlap the trigger, a naive array can receive the same actor more than once. A set says "this actor is either in the group or it is not."

Sets are not sorted lists. If you need "first", "last", "next", or a stable display order, convert deliberately or use an array with explicit sorting.

Maps

Use a map when you have a reliable key and want the matching value.

Map ItemCounts:
    Key = ItemId (Name)
    Value = Count (Integer)

Pickup Potion:
    if ItemCounts contains Potion:
        ItemCounts[Potion] = ItemCounts[Potion] + 1
    else:
        Add Potion -> 1

Good keys are stable identifiers:

  • Name item IDs such as Potion_Small;
  • Gameplay Tags such as Surface.Stone or Weapon.Rifle;
  • enum values such as EDamageType::Fire;
  • object references when the object lifetime is clearly owned elsewhere.

Bad keys are values that drift or are not unique:

  • display text the player sees;
  • actor names generated at runtime;
  • floats from measurements;
  • object references that can be destroyed without cleanup.

Maps return "found or not found" style answers. Treat a missing key as a real branch, not an exceptional crash:

Find ItemCounts by ItemId
-> Found?
   true: update existing count
   false: add default count

For Each Loop

For Each Loop takes a container and runs the loop body once for each element. For arrays, it gives the current element and array index. For sets/maps, the available pins depend on the container node you are using.

For Each Loop Enemies
-> Array Element
-> Is Valid
-> Apply Damage

The loop is still one execution path in the current frame. If you run a loop over 500 actors from Tick, that is 500 iterations every frame. The node is convenient; it is not free.

Be careful when changing the container you are looping over. The beginner-safe pattern is to collect changes separately, then apply them after the loop:

For Each CurrentOverlappers
-> if actor invalid:
       add actor to PendingRemoval

For Each PendingRemoval
-> remove from CurrentOverlappers

When containers fail

Containers usually fail by giving you an empty result, a warning, or stale references.

Symptom Likely cause Fix shape
Accessed None from an array element The element is an object reference that is empty or destroyed. Is Valid each element before calling into it.
Array index warning The index is outside 0..Length - 1. Check Length, clamp, or use For Each instead of manual indices.
A set "does not add" the second copy Sets keep unique values. Use an array if duplicates are meaningful, or store a count in a map.
Map lookup returns not found The key was never added, changed, or is not the same type/value. Branch on Find/Contains and add a default path.
Loop sees old actors You stored object references and the actors were destroyed. Remove on EndOverlap/EndPlay and guard with Is Valid.
Order changes unexpectedly You used a set or map where display order matters. Use an array or build a sorted array for display.

What containers do not do

  • They do not create the actors, widgets, or assets they reference.
  • They do not keep an actor alive after it is destroyed.
  • They do not replicate just because the variable is a container. Replication still needs the owning actor and variable settings to be correct.
  • They do not save themselves to disk unless you copy the values into a SaveGame object.
  • They do not make a bad ownership model good. Decide whether the character, controller, component, GameInstance, or SaveGame owns the data.

The pattern everyone actually uses

For a door that opens while any player is inside:

Variable CurrentUsers: Set of BP_PlayerCharacter references

BeginOverlap:
    Other Actor -> Cast/Interface filter
    Add player to CurrentUsers
    if CurrentUsers length > 0:
        OpenDoor

EndOverlap:
    Remove player from CurrentUsers
    if CurrentUsers length == 0:
        CloseDoor

For a small inventory:

Struct FInventoryEntry:
    ItemId (Name)
    DisplayName (Text)
    Count (Integer)

Array InventorySlots for UI order
Map ItemIdToSlotIndex for quick lookup

Start with one container. Add the second only when the graph proves you need both display order and fast lookup.

Lookalikes - which one do I want?

Tool Use when Watch out
Array You need ordered zero/one/many values of one type. Check Length before Get by index.
Set You need unique membership and do not care about order. Do not rely on iteration order for UI.
Map You need to find a value by a stable key. Missing keys are normal; branch on Find/Contains.
Struct Several fields should travel as one value. A struct is one value, not a list.
Data Table Many rows of the same struct belong in data. Rows need a struct shape and stable row names.
Data Asset One authored asset should hold a chunk of reusable data. Asset references are not live actor references.

Rule of thumb: array for order, set for uniqueness, map for lookup.

Going deeper