Whatever message this page gives is out now! Go check it out!

Sets in ColdFusion

Last update:
May 18, 2026
ColdFusion includes sets as a first-class, native data type, a collection that holds a collection of unique elements.

What is a set?

A Set is a fundamental abstract data type that stores a collection of unique elements. Unlike arrays or lists, their primary focus is on existence and uniqueness.
Sets come from mathematical set theory and implement the same fundamental operations: union, intersection, difference, and symmetric difference, making them the natural tool for any problem that involves comparing groups of things.
ColdFusion sets support both ordering (ordered or unordered) and case handling (case-sensitive or case-insensitive). Sets can store any value type (objects, arrays, functions, primitives).

Why use sets

The problem with arrays for uniqueness
Arrays are the go-to collection in ColdFusion, but they were never designed for uniqueness guarantees. Keeping an array free of duplicates requires you to check membership before every insert:
// Array approach — deduplicating 100,000 values
arrayData = [];
for (i = 1; i <= 100000; i++) {
    value = randRange(1, 5000);
    if (!arrayFind(arrayData, value)) {   // O(n) scan every time
        arrayAppend(arrayData, value);
    }
}
arrayFind() scans every existing element until it finds a match or exhausts the array. As the array grows, each check becomes slower. For 100,000 insertions, the cumulative cost can be enormous.
How sets solve it
A set uses a hash-based internal structure. Adding an element, checking membership, and removing an element are all O(1), constant time, regardless of how many elements the set already contains:
// Set approach — same 100,000 values
setData = SetNew();
for (i = 1; i <= 100000; i++) {
    value = randRange(1, 5000);
    setData.add(value);   // O(1), duplicates ignored automatically
}

When to use a set

Use a set when one or more of these is true:
When to use sets
SituationWhy a set fits
You need a collection with no duplicates.Sets enforce uniqueness automatically.
You frequently check whether a value exists..has() is O(1) vs arrayFind()'s O(n).
You need to combine or compare two groups.Union, intersection, and difference are built-in.
You're building tags, permissions, or feature flags.Membership-centric data is a natural set.
You're deduplicating a list or array.setNew(array) does it in one call.
You're modeling relationships (friends, categories, roles).Set algebra maps directly to the problem.
Stick with arrays when element order matters, when you need indexed access (myArray[3]), or when duplicates are meaningful.

Create a set

Empty set
Creates an unordered set backed by a hash set internally. Element iteration order is not guaranteed.
mySet = setNew();
Ordered set
Creates a set that remembers the insertion order of elements. Iteration will visit elements in the order they were added. Slightly more memory overhead than an unordered set.
mySet = setNew("ordered");
Set from an array
Passes an existing array to setNew(). All duplicate values are discarded. The result is the deduplicated set of values from the array. This is the fastest way to deduplicate an array.
<cfscript>
    arr = [1, 2, 3, 4, 5, 5, 4, 3, 2, 1, 23];
    uniqueVals = setNew(arr);
    writeDump(uniqueVals) // Output: Set with unique values {1, 2, 3, 4, 5, 23}
</cfscript>
Set with any value types
Sets can hold any ColdFusion value — numbers, strings, closures, structs, or any other object:
<cfscript>
    closure = () => 2 + 3;
    mySet = setNew();
    mySet.add(closure);
    mySet.add(2);
    mySet.add("hello");
    writeDump(mySet); // Output: Set with values {closure, 2, "hello"}
</cfscript>

Core operations

.add(value)
Adds a value to the set. If the value already exists, the call is a no-op and the set is unchanged.
<cfscript>
    mySet = setNew();
    mySet.add(1);
    mySet.add(2);
    mySet.add(2); // duplicate — ignored
    mySet.add(3);
    writeDump(mySet)
    // Output: Set with values {1, 2, 3}
</cfscript>
.has(value)
Returns true if the value is in the set, false otherwise. This is O(1) — it does not scan the collection.
<cfscript>
    mySet = setNew();
    mySet.add(10);
    mySet.add(20);
    writeOutput(mySet.has(10)); // true
    writeOutput(mySet.has(99)); // false
</cfscript>
.delete(value)
Removes a value from the set. If the value does not exist, the call is a no-op.
<cfscript>
    mySet = setNew();
    mySet.add(1);
    mySet.add(2);
    mySet.add(3);
    mySet.delete(2);
    writeDump(mySet);
    // mySet now contains: {1, 3}
</cfscript>
.size()
Returns the number of elements currently in the set.
<cfscript>
    mySet = setNew();
    mySet.add("a");
    mySet.add("b");
    mySet.add("c");
    writeOutput(mySet.size()); // 3
</cfscript>
.clear()
Removes all elements from the set, leaving an empty set.
<cfscript>
    mySet = setNew();
    mySet.add(1);
    mySet.add(2);
    writeOutput(mySet.size()); // 2
    mySet.clear();
    writeOutput(mySet.size()); // 0
</cfscript>
Complete core example:
<cfscript>
    set = setNew();
    set.add(10);
    set.add(20);
    set.add(30);
    set.add(20); // duplicate — ignored

    writeDump(set);

    writeOutput("Size: " & set.size()); // 3
    writeOutput("Has 20: " & set.has(20)); // true
    writeOutput("Has 99: " & set.has(99)); // false

    set.delete(20);
    writeOutput("After delete, has 20: " & set.has(20)); // false
    writeOutput("Size after delete: " & set.size()); // 2

    set.clear();
    writeOutput("Size after clear: " & set.size()); // 0
</cfscript>

Set algebra operations

These functions take two sets and return a new set. Neither input set is modified.
setUnion(setA, setB)
Returns a new set containing all elements that appear in either setA or setB (or both).
<cfscript>
    setA = setNew("ordered");
    setA.add(1); setA.add(2); setA.add(3); setA.add(4);

    setB = setNew("ordered");
    setB.add(3); setB.add(4); setB.add(5); setB.add(6);

    union = setUnion(setA, setB);
    writeDump(union); // {1, 2, 3, 4, 5, 6}
</cfscript>
Real-world: combining two product catalogs, merging permission sets, collecting all participants from multiple event lists.
setIntersection(setA, setB)
Returns a new set containing only the elements that appear in both setA and setB.
intersection = setIntersection(setA, setB);
writeDump(intersection); // {3, 4}
Real-world: finding customers who bought from both category A and B, finding features supported on all selected platforms, finding common tags between two articles.
setDifference(setA, setB)
Returns a new set containing elements that are in setA but not in setB. Order matters: setDifference(A, B)setDifference(B, A).
diff = setDifference(setA, setB);
writeDump(diff); // {1, 2}
Real-world: finding users who haven't completed onboarding, finding products in one store that aren't in another, finding permissions a user has that a role doesn't grant.
setSymmetricDifference(setA, setB)
Returns a new set containing elements that are in either set but not both — the inverse of intersection.
symDiff = setSymmetricDifference(setA, setB);
writeDump(symDiff); // {1, 2, 5, 6}
Real-world: finding items that changed between two snapshots, detecting configuration drift, finding exclusive items for a loyalty comparison.
setIsDisjointFrom(setA, setB)
Returns true if the two sets share no common elements — their intersection is empty.
<cfscript>
    bluetoothProducts = SetNew(["Mouse X", "Headphones Z", "Speaker Q"]);
    usbCProducts = SetNew(["Laptop A", "Charger B", "Hub C"]);

    if (setIsDisjointFrom(bluetoothProducts, usbCProducts)) {
        writeOutput("Bluetooth and USB-C are separate categories");
    }
</cfscript>
Real-world: validating that two permission groups don't overlap, checking that two product categories are mutually exclusive, verifying no duplicate users appear in two separate queues.

Iterating over a set

Use a standard for...in loop to iterate over every element in a set:
mySet = setNew("ordered");
mySet.add("Alice");
mySet.add("Bob");
mySet.add("Charlie");

for (name in mySet) {
    writeOutput(name & "<br>");
}
// Alice
// Bob
// Charlie
For an unordered set, iteration order is not defined. Use setNew("ordered") if you need to process elements in insertion order.

Converting between sets and other types

Set → Array: .ToArray()
Converts the set to a ColdFusion array. Useful when you need indexed access or need to pass the result to a function expecting an array.
setA = setNew("ordered");
setA.add(10); setA.add(20); setA.add(30);

arr = setA.ToArray();
writeDump(arr);   // [10, 20, 30]
Set → Delimited list: setToList(set, delimiter)
Converts the set to a string with elements joined by a delimiter.
friends = setNew();
friends.add("Alice");
friends.add("Bob");
friends.add("Charlie");

writeOutput(setToList(friends, ", "));   // "Alice, Bob, Charlie"
Array → Set: setNew(array)
Pass any array to setNew() and it becomes a set, with duplicates automatically removed:
rawList = ["red", "blue", "red", "green", "blue", "red"];
uniqueColors = setNew(rawList);
writeOutput(uniqueColors.size());   // 3

Real-world use cases

1. Deduplicating data
The most common use of a set is removing duplicates from a list or query result:
<cfscript>
    // Tags from multiple blog posts — may contain duplicates
    allTags = ["cfml", "api", "json", "cfml", "rest", "api", "performance"];
    uniqueTags = setNew(allTags);

    writeOutput("Unique tags: " & setToList(uniqueTags, ", "));
    // cfml, api, json, rest, performance
</cfscript>
2. Permissions and role management
Sets express permission logic naturally:
<cfscript>
    // Permissions granted by roles
    adminPerms = SetNew(["read", "write", "delete", "publish"]);
    editorPerms = SetNew(["read", "write", "publish"]);
    viewerPerms = SetNew(["read"]);

    // What can an admin do that an editor can't?
    adminOnly = setDifference(adminPerms, editorPerms);
    writeOutput(setToList(adminOnly, ", ")); // delete

    // What do admin and editor share?
    shared = setIntersection(adminPerms, editorPerms);
    writeOutput(setToList(shared, ", ")); // read, write, publish
</cfscript>
3. E-Commerce product feature filtering
<cfscript>
    wirelessProducts = SetNew(["Laptop A", "Mouse X", "Keyboard Y", "Headphones Z"]);
    bluetoothProducts = SetNew(["Mouse X", "Headphones Z", "Speaker Q"]);
    usbCProducts = SetNew(["Laptop A", "Charger B", "Hub C"]);

    // Products with BOTH wireless AND Bluetooth
    wirelessBluetooth = setIntersection(wirelessProducts, bluetoothProducts);
    writeOutput("Wireless + Bluetooth: ");
    writeDump(wirelessBluetooth);
    // {Mouse X, Headphones Z}

    // Wireless products that DON'T have Bluetooth
    wirelessOnly = setDifference(wirelessProducts, bluetoothProducts);
    writeOutput("Wireless only: ");
    writeDump(wirelessOnly);
    // {Laptop A, Keyboard Y}

    // Products with wireless OR USB-C
    modernProducts = setUnion(wirelessProducts, usbCProducts);
    writeOutput("Wireless OR USB-C: ");
    writeDump(modernProducts);
    // {Laptop A, Mouse X, Keyboard Y, Headphones Z, Charger B, Hub C}

    // Confirm Bluetooth and USB-C don't overlap
    if (setIsDisjointFrom(bluetoothProducts, usbCProducts)) {
        writeOutput("Bluetooth and USB-C are separate categories");
    }
</cfscript>
4. Social friend suggestions
A classic "people you may know" algorithm using set operations:
<cfscript>
    // User's current friends
    userFriends = SetNew(["Alice", "Bob", "Charlie"]);

    // Friends of each friend
    aliceFriends = SetNew(["Bob", "David", "Eve"]);
    bobFriends = SetNew(["Alice", "Frank", "Grace"]);
    charlieFriends = SetNew(["Alice", "David", "Henry"]);

    // Collect all friends-of-friends using union
    friendsOfFriends = setNew();
    for (friend in userFriends) {
        if (friend == "Alice") friendsOfFriends = setUnion(friendsOfFriends, aliceFriends);
        if (friend == "Bob") friendsOfFriends = setUnion(friendsOfFriends, bobFriends);
        if (friend == "Charlie") friendsOfFriends = setUnion(friendsOfFriends, charlieFriends);
    }

    // Remove people the user already knows → people to suggest
    suggestions = setDifference(friendsOfFriends, userFriends);

    writeOutput("Friend suggestions: " & setToList(suggestions, ", "));
    // David, Eve, Frank, Grace, Henry
</cfscript>

Performance characteristics

Performance characteristics
OperationArraySet
Add elementO(1)O(1)
Check membershipO(n) via arrayFind()O(1) via .has()
Remove elementO(n) to find, then shiftO(1) via .delete()
Union of two collectionsO(n²) with manual dedupO(n) via setUnion()
IntersectionO(n²) nested loopsO(n) via setIntersection()
DeduplicationO(n²) arrayFind per itemO(n) setNew(array)
The following benchmark inserts 100,000 random values (range 1–5,000) while maintaining uniqueness:
<cfscript>
    // Array: check before each insert
    startTime = getTickCount();
    arrayData = [];
    for (i = 1; i <= 100000; i++) {
        value = randRange(1, 5000);
        if (!arrayFind(arrayData, value)) {
            arrayAppend(arrayData, value);
        }
    }
    arrayTime = getTickCount() - startTime;
    writeOutput("Array: " & arrayTime & "ms");

    // Set: just add — duplicates handled automatically
    startTime = getTickCount();
    setData = SetNew();
    for (i = 1; i <= 100000; i++) {
        value = randRange(1, 5000);
        setData.add(value);
    }
    setTime = getTickCount() - startTime;
    writeOutput("Set: " & setTime & "ms");

    writeOutput("Set is " & numberFormat(arrayTime / setTime, "0.00") & "x faster");
    // Typical result: 50–100x faster
</cfscript>
The speedup grows as the dataset grows because the array's O(n) membership check compounds with every insertion.

API quick reference

Creation
Creation functions
FunctionDescription
setNew()Create an empty unordered set.
setNew("ordered")Create an empty ordered set (preserves insertion order).
setNew(array)Create a set from an array, removing duplicates.
Instance methods
Instance methods
MethodReturnsDescription
.add(value)voidAdd a value; no-op if already present.
.has(value)booleantrue if value is in the set.
.delete(value)voidRemove a value; no-op if not present.
.size()numberNumber of elements in the set.
.clear()voidRemove all elements.
.ToArray()arrayConvert the set to a ColdFusion array.
Global functions
Global functions
FunctionReturnsDescription
setUnion(setA, setB)setAll elements in A or B (or both).
setIntersection(setA, setB)setOnly elements in both A and B.
setDifference(setA, setB)setElements in A that are not in B.
setSymmetricDifference(setA, setB)setElements in either A or B, but not both.
setIsDisjointFrom(setA, setB)booleantrue if A and B share no elements.
setToList(set, delimiter)stringJoins all elements with the given delimiter.

See also

Share this page

Was this page helpful?
We're glad. Tell us how this page helped.
We're sorry. Can you tell us what didn't work for you?
Thank you for your feedback. Your response will help improve this page.

On this page