[UE5] Blueprint Array, Set, and Map Basics: Choosing Between the Three Containers

Created: 2026-07-20Last updated: 2026-09-05

When one variable is not enough, containers take over. Diagrams the difference between Array (ordered), Set (no duplicates), and Map (looked up by key) plus their main nodes, with a hands-on counting inventory quantities in a Map.

Building an inventory, you line up variables named Item1 , Item2 , Item3 . Managing enemies, you create Enemy1 and Enemy2 . Every increase means adding another variable and similar nodes.

That is what containers are for. Blueprint has three kinds, Array, Set, and Map , all containers for holding several values of the same type. Choose by asking whether you want to keep the order, to record only the kinds, or to know a quantity from an ID . Here we record the same pickups in all three and compare what each can tell us.

The three containers Array, Set, and Map side by side

What You'll Learn

  • Array = ordered / Set = no duplicates / Map = looked up by key
  • Containers are chosen with the toggle button to the right of a variable's type
  • Array's main nodes, and how to fix Index out of bounds
  • Why adding or removing during a loop skips the next element
  • Hands-on: an inventory managing item IDs and quantities with a Map

Sponsored

The difference between the three containers

All three gather multiple pieces of data. One item inside is an element . What differs is how you search and retrieve.

ContainerHow it holds thingsQuestions it answers wellWhat it is bad at
ArrayIn order. Duplicates allowed"What is the third?" "How many total?"Finding a value means comparing in order
SetNo duplicates. No order"Do I have this?"There is no "third"
MapKey and value pairs. No order"What is this key's value?"It cannot hold the same key twice

Put into game terms, the choice becomes clear.

  • Array : a log in pickup order, party ordering, waypoint patrol order. Things where the order itself carries meaning
  • Set : IDs of items already obtained, unlocked stages, monsters registered in a catalog. Things you do not want registered twice
  • Map : item ID to quantity, player name to score, key name to setting. Things you want to look up by something

A key is the handle specifying the data you want. Holding "Herb → 3" in a Map makes Herb the key and 3 the value. Its role differs from an array's position number.

Array records pickup order, Set records the kinds found, and Map records quantities per ID. Comparing all three with herbs and potions

Containers toggle to the right of the type

In Blueprint, you first choose the element type, then specify whether you hold one of them or gather them into an Array, Set, or Map.

Create a variable in the My Blueprint panel and the Details panel shows Variable Type . There is a small button to the right of the type dropdown offering four choices.

DisplayMeaning
Single VariableA normal variable (one)
ArrayAn array
SetA set
MapA dictionary. Choosing it adds another field for the value type
The container toggle to the right of the variable type dropdown, with its four choices

Only Map gives you two fields. The left is the key type and the right is the value type. For "item ID (Name) → quantity (Integer)", set Name on the left and Integer on the right.

Name is the type used for identifiers like Herb and Potion. It suits separating the text "Herb" shown on screen from the ID used in logic. Some types cannot be Set elements or Map keys, so we standardize item IDs on Name here.

Sponsored

Array's main nodes

Array is the most used of the three. Drag an array variable into the graph and pull from its pin to see the candidates.

NodeWhat it doesNotes
AddAppends to the endReturns the index it was added at
InsertInserts at a given indexLater elements shift back by one
Remove IndexRemoves by numberLater elements shift forward by one
Remove ItemRemoves by contentRemoves all matches
Get (a copy)Retrieves by numberSpecifying out of range causes an error
Set Array ElemRewrites the value at a given indexWith Size to Fit off it uses an existing index; on, it grows the array as needed
LengthReturns the element count0 when empty
Last IndexReturns the last index (Length - 1)-1 for an empty array
Contains ItemReturns whether it is contained as Booleantrue if found, false if not
Find ItemReturns the index foundReturns -1 when not found
Is Valid IndexReturns whether that index is usableUse it as a safety check before Get

An index is the number specifying a position in an Array. It starts at 0 , so three elements are numbered 0, 1, 2. Length is the count 3 and Last Index is the final number 2. Boolean (bool) is the type handling true when a condition holds and false when it does not.

An Array of 3 has indices 0, 1, 2 and no index 3. An empty Array has Length 0 and Last Index -1, with nothing to read

Getting with an out-of-range index prints something like this to the Output Log. The wording varies by node and version, but index and length let you trace the cause.

Blueprint Runtime Error: "Attempted to access index 3 from array 'PickupLog' of length 3!"

It means "index 3 was requested from an array of 3". Index 3 is the fourth from the start, so it does not exist. The count and the last index differ by one.

There are two ways to prevent it. Feed the checked Boolean into a Branch's Condition and use Get only on the True side. A Branch splits execution into True and False by condition.

  • Check with Is Valid Index before Get : use this when the index comes from outside (a UI click position, a saved value)
  • Check for empty before reading the last element too : Last Index is handy but is -1 on an empty array. Either Get only on the True side of a Length > 0 Branch, or check Last Index with Is Valid Index

Get (a copy) retrieves a copy of the value. When the array holds structs, rewriting the retrieved copy does not change the original element. Use Set Array Elem to write it back. This trips people up, so the struct article covers the mechanism and the fix in detail.

For Each Loop and modifying during a loop

Use For Each Loop to process an array one element at a time. Pull from an array pin and it appears among the candidates.

PinContents
Loop BodyRuns for each element
Array ElementThe content at that moment
Array IndexThe index at that moment
CompletedRuns once after everything finishes

To stop partway, use For Each Loop with Break . Sending execution into the Break pin ends the loop there. Handy for "stop at the first match".

What to watch for is adding to or removing from the array you are iterating, inside a For Each Loop . The count and indices change, so you may not process things in the order you expected.

Removing an element mid-loop shifts later elements forward, skipping the next one, shown with indices

The reason is clear from the mechanism. For Each Loop simply advances an index from 0 . With A, B, C, D , removing index 1 ( B ) shifts C to index 1 and D to index 2. The loop looks at index 2 next, so C , which moved to index 1, is never processed .

The same causes you to miss adjacent targets when "removing enemies at 0 HP from an array".

The clearest first approach is not modifying the original array until you finish reading it.

  • Gather removal targets in a separate array : during the loop only add to RemoveTargets , and Remove Item them together after Completed . The most straightforward and readable method
  • Build a new array of what remains : Add only the matching elements to another array and swap it into the original variable at the end

The same goes for additions: gathering into a separate array and adding after processing keeps this loop's scope clear. Distinguish updating existing element values from changing counts and positions.

Sponsored

Set: the container with no duplicates

A Set cannot hold the same value twice . Add ing a value already present does not increase the count. It is not an error either; it is quietly ignored.

NodeWhat it does
AddAdds. Nothing happens if it is already there
RemoveRemoves by content
ContainsReturns whether it is contained as a bool
LengthReturns the element count
To ArrayConverts to an array (use this to loop)

Sets suit cases where you only need to know whether you have something .

  • IDs of items already obtained (opening the same chest twice adds nothing)
  • IDs of unlocked stages
  • Monster IDs registered in a catalog
  • IDs of NPCs you have already talked to
The difference between Array and Set. A Set's count does not grow when you Add the same value

Choosing a Set states structurally that "this list never holds the same ID twice". Arrays also have Add Unique , which does not add duplicates. Array plus Add Unique when you also want order; Set when recording presence is the main purpose.

Sets have no indices . There is no Get(0) , and order is not guaranteed. To process one at a time, convert with To Array and loop over that.

Map: the container looked up by key

A Map holds key and value pairs . For example the ID Herb paired with a quantity of 3.

NodeWhat it doesNotes
AddRegisters a key and valueOverwrites if the key exists
FindRetrieves a value by keyReturns the value and a found bool
ContainsReturns whether the key exists as a bool
RemoveRemoves by key
KeysReturns the keys as an arrayUse this to loop
ValuesReturns the values as an array
LengthReturns the number of pairs

We use a Map here to know a quantity from an item ID . Map<Name, Integer> denotes "a Map with Name keys and integer values". Find with Herb and you retrieve its quantity.

Two things to keep in mind with Maps.

First, Add overwrites. It is not "do nothing if it already exists". To increase a count, the flow is Find the current value, add 1, and put it back with Add . We build that in the hands-on.

Reading Herb's 3 from the Map, adding 1, and writing 4 back to the same Herb. Herb's row does not multiply and Potion's 1 is unchanged

Second, order is not guaranteed. The array from Keys is not necessarily in insertion order. Removing elements can rearrange it too. To fix display order, keep a separate Array for it. Order that Array as Herb, Potion, and Find the Map by those IDs, and you can display them without relying on insertion order.

Values retrieved by Find are copies too. When the value type is a struct, rewriting what Find returned does not change the original Map. Putting it back with Add on the same key is reliable (see the struct article).

Sponsored

Hands-On: build an inventory that counts quantities

An RPG's inventory, a roguelike's floor drops, a survival game's crafting materials. "Pick things up and count them" appears in every genre. Here we record the same pickups in all three containers at once and see with our own eyes that each answers a different question .

What it looks like running

After picking up herbs three times and a potion once, the three containers hold this.

After 3 herbs and 1 potion, Array has 4 entries, Set has 2, and Map has herb 3 and potion 1, shown side by side
ContainerContentsThe question it answers
PickupLog (Array)Herb, Herb, Herb, Potion (4)"What did I pick up third?"
FoundItems (Set)Herb, Potion (2)"Have I ever seen a Potion?"
Inventory (Map)Herb → 3, Potion → 1"How many herbs do I have?"

Reproduction conditions

Create a Blueprint BP_ContainerTester with Actor as its parent and place one in the level. This exercise calls the pickup logic from BeginPlay, so no floor items or input are needed. Create the following variables in Variables, with all defaults empty after compiling.

Variable nameTypeContainerDefault
PickupLogNameArray(empty)
FoundItemsNameSet(empty)
InventoryName → IntegerMap(empty)

Switch containers with the button to the right of Variable Type in the Details panel. Choosing Map for Inventory gives two fields; set Name on the left and Integer on the right .

Create the PickupItem function

Create a new PickupItem under Functions in the My Blueprint panel and add one input pin.

Input pinType
ItemIDName

Leave the function's Pure off. Add to the Array history and the Set of kinds, then update the Map quantity. The nodes share the name Add but differ by container, so place a Get of each container variable and drag from that pin to create the node.

First, record the pickup history and the kinds found.

  1. From PickupItem's entry, wire white exec to the Array Add. Target Array is PickupLog and New Item is the function's ItemID.
  2. Continue to the Set Add. Target Set is FoundItems and New Item is the same ItemID.
Passing PickupLog to the Array Add's Target Array and the function's ItemID to New Item

Now put the same ID into the Set. Duplicates collapse into one automatically.

Passing FoundItems to the Set Add's Target Set and the same ItemID to New Item

The Get ItemID in the diagram reads the input passed to the function. Wiring the same value from the ItemID pin on the function's entry is fine too. Do not create a new Class Variable.

Next, update the quantity. With PickupItem open, create an Integer Local Variable NewCount with default 0. It holds the count we are about to write. A Local Variable is used only inside that function (see Blueprint variable basics).

Create Find and a Map Add from a Get of Inventory and wire them as follows.

Where to connectValue to pass
Find's Target MapInventory
Find's KeyItemID
Integer + 's AFind's Value
+ 's B1
Map Add's Target MapInventory
Map Add's KeyItemID
Set NewCount's valueThe + result
Map Add's ValueGet NewCount

Connect the Set Add's white exec output to Set NewCount, and its output to the Map Add's exec input. That computes the new count before writing to the Map. Find and the integer addition take no white exec wire. They are evaluated when Set NewCount needs the value.

Finding ItemID's quantity in Inventory, adding 1, and storing it in NewCount. An unregistered Integer is 0, so the first becomes 1

Write the counted result back to the same key.

Passing NewCount to the Map Add's Value. Target Map is Inventory and Key is ItemID, writing back that ID's quantity

The point is Find the current count, add 1, and put it back on the same key . The Map Add is not a node that increments automatically. Passing 1 to Value every time would overwrite with 1 no matter how many you pick up.

Our Map's value is an Integer, so Finding an unregistered key gives Value 0. 0 + 1 makes the first one, which is why this tally does not need Find's found Boolean.

For logic that distinguishes "unregistered" from "registered but zero", check Find's Boolean output with a Branch as well. The value 0 alone cannot tell them apart.

Call it and confirm

Call it four times from BeginPlay in the Event Graph. Compile after creating the function, place four PickupItem call nodes, and chain the white exec wires. Use Herb for the first three ItemIDs and Potion for the last.

Event BeginPlay
  → PickupItem (ItemID: Herb)
  → PickupItem (ItemID: Herb)
  → PickupItem (ItemID: Herb)
  → PickupItem (ItemID: Potion)

  → Print String (Log count)
  → Print String (Found kinds)
  → Print String (Herb quantity)

The numbers for the three Print Strings are PickupLog's Length, FoundItems' Length, and the Value from Finding Inventory with Key = Herb. Length and Find have no exec pins, so connect their numeric outputs for display.

Convert the numbers to String and feed them into Append 's B. Put Log: , Found: , and Herb: into A in turn and pass Append's result to Print String's In String. Connecting an Integer wire to a String input inserts a conversion node.

Set Print String's Duration to 10 seconds, compile, save, and Play. Seeing these three messages means success. Read the labels and numbers rather than their vertical order on screen.

Log: 4
Found: 2
Herb: 3

Four pickups make the Array 4 , two kinds make the Set 2 , and three herbs make the Map value 3 . The point of this hands-on is that the same four calls produce three different answers .

Now add another PickupItem (Herb) between the fourth PickupItem and the first Print String. Log becomes 5, Found stays 2, and Herb becomes 4. Only the Set not growing is exactly the Set's nature.

Troubleshooting:

  • Herb is always 1 → you put 1 straight into Add without adding Find's result
  • The same item is counted separately → check for ID spelling differences like Herb versus Herbs . Name is case-insensitive, so Herb and herb are the same ID
  • Found becomes 4FoundItems is an Array, not a Set. Check the container setting in the Details panel
  • Log stays 0 → the Add for PickupLog has its Target connected to a different variable
  • No Print String outputPickupItem 's exec pins are not chained through (see Print String debugging)

In a real game you call PickupItem from logic receiving touched items or rewards. Here, four calls confirmed you can extract "order", "kind", and "quantity" separately from the same events.

Once an item's contents grow to "name, attack, and icon", it is time to make the value a struct. Build S_Item in the struct article and use it directly as a Data Table row.

To move on to laying inventory out on screen and using it, inventory implementation is the next subject.

Sponsored

Bonus: Good to Know Up Front

  • For large searches, revisit how you search : Array's Contains Item compares values in order. If searching a large dataset repeatedly is heavy, first check how often you call it, and consider managing it with a Set or Map if that fits. For small lists, prioritize the order and meaning your data needs
  • Arrays can be filled up front : you can enter elements in advance in the Details panel's Default Value. For fixed counts like "five patrol points", setting them in the level is easier to verify than Add ing at runtime
  • To carry quantities to the next session, save them : this Actor's Map is lost when you stop Play. Create a Map of the same type in a SaveGame, copy the values, and call the save logic to carry it over. Creating a variable does not save it to a file (see saving and loading)
  • Fixed content belongs in a DataTable : data decided at design time , like "the list of all items", is easier to manage in a DataTable than hand-entered into a Blueprint array (see Data Table basics and data-driven design with Data Assets)
  • Do not forget the empty case : calling Get(0) on an array whose Length is 0 errors. Logic like "target the first enemy" should always pair with a Length > 0 check . This kind of slip is also collected in common Blueprint mistakes

Summary

QuestionContainer to choose
Does order carry meaning?Array
Do you want no duplicates, or just presence?Set
Do you want to look something up by a handle?Map
  • Containers switch with the button to the right of the variable type . Only Map gets two fields
  • Array indices start at 0 . Length and the maximum index differ by one
  • Do not change the indices you are processing during a loop. Start by gathering targets in a separate array
  • A Map's Add overwrites . To increase a count, do Find → +1 → Add

Once you can gather multiple values, you can try organizing states like "idle, moving, attacking" next. That is covered in managing state with Enum and Switch.

Keep the pickup order, record the kinds found, count the quantities. From the same pickups, you choose the container that matches the information you want to keep.

Further Reading

Unreal Engine Notes in this section98