One of the many new exciting features in Swift 1.2 is the introduction of a new type, Set. Even if you’ve never come across the type before, you may well have hand coded the functionality of a set when you’ve wanted to, for example, compare two arrays to find the commonality between them. Or you may have used similar functionality when you’ve used unions and joins in SQL
Sets contain unordered distinct collections of objects and allow you to implement set theory Venn diagram functionality against them.
Let’s kick off by creating two sets of integers from arrays. One containing the odd numbers and the other the even numbers up to and including ten:
let odd = Set([1, 3, 3, 3, 5, 7, 9]) // {5, 7, 3, 1, 9}
let even = Set([2, 2, 2, 2, 2, 2, 4, 6, 8, 8, 10]) // {6, 10, 2, 4, 8}
The first thing you’ll notice is that sets contain distinct values: despite the fact my array of even numbers contains six instance of ‘2’, the set only contains one.
To see if there’s any overlap between odd and even, isDisjoint() returns a Boolean indicating that no members exist in both sets:
let oddDisjointWithEven = odd.isDisjointWith(even) // true
To combine these sets together, we’ll use the union() method to give us a new Set instance named allNumbers:
let allNumbers = odd.union(even) // {10, 2, 9, 4, 5, 7, 6, 3, 1, 8}
To do some more tinkering, I’ll create my own set named xyzzyNumbers:
let xyzzyNumbers = Set([1, 2, 3, 4]) // {2, 3, 1, 4}
…this new set does contain some odd numbers, so I’d expect isDisjoint() again my odd numbers to be false:
let xyzzyDisjointWithOdd = xyzzyNumbers.isDisjointWith(odd) // false
To get the odd numbers in xyzzy that are below ten, I can use the intersect() method:
let xyzzyOddNumbers = xyzzyNumbers.intersect(odd) // {3, 1}
…and likewise with even:
let xyzzyEvenNumbers = xyzzyNumbers.intersect(even) // {2, 4}
The isSubset() method returns true if one set is a subset of the other. xyzzy isn’t a subset of odd, because it contains even numbers, however it is a subset of allNumbers:
let xyzzyIsSubsetOfOdd = xyzzyNumbers.isSubsetOf(odd) // false
let xyzzyIsSubSetOfAll = xyzzyNumbers.isSubsetOf(allNumbers) // true
…and this implies that allNumbers is a superset of xyzzy:
let allIsSupersetOfXyzzy = allNumbers.isSupersetOf(xyzzyNumbers) // true
I can also subtract one set from another. Here, I remove all of the numbers from xyzzy from my odd numbers:
let oddNumbersSubtractXyzzy = odd.subtract(xyzzyNumbers) // {5, 7, 9}
Sets aren’t limited to integers, they can be created from any hashable types, such as strings:
let colors = Set(["red", "orange", "purple"]) // {"orange", "purple", "red"}
let fruit = Set(["apple", "banana", "orange"]) // {"banana", "apple", "orange"}
let fruityColors = colors.intersect(fruit) // {"orange"}
let nonFruityColors = colors.exclusiveOr(fruit) // {"banana", "purple", "red", "apple"}
But types can’t be mixed, so this will not compile:
let evenColors = colors.intersect(even)
Addendum - Creating Sets From Your Own Data Types
If you want to create sets of your own data type, you need to ensure your struct or class conforms to the Hashable protocol which extends the Equatable protocol. This means you’ll need your data data to implement an equality function (‘==‘) and be able to return a hashed value of itself.
let name: String
let swims: Bool
let flies: Bool
let walks: Bool
let legCount: Int
var hashValue: Int
{
get
{
returnname.hashValue + (swims ? 10 : 0) + (flies ? 100 : 0) + (walks ? 1000 : 0) + legCount
}
}
func == (lhs: Creature, rhs: Creature) -> Bool
{
return lhs.hashValue == rhs.hashValue
}
struct Creature: Hashable
{
init(name: String, swims: Bool, flies: Bool, walks: Bool, legCount: Int)
{
self.name = name
self.swims = swims
self.flies = flies
self.walks = walks
self.legCount = legCount
}
let name: String
let swims: Bool
let flies: Bool
let walks: Bool
let legCount: Int
var hashValue: Int
{
get
{
returnname.hashValue + (swims ? 10 : 0) + (flies ? 100 : 0) + (walks ? 1000 : 0) + legCount
}
}
}
let ant = Creature(name: "Ant", swims: false, flies: false, walks: true, legCount: 6)
let bumbleBee = Creature(name: "Bumble Bee", swims: false, flies: true, walks: false, legCount: 6)
let cat = Creature(name: "Cat", swims: false, flies: false, walks: true, legCount: 4)
let flyingFish = Creature(name: "Flying Fish", swims: true, flies: true, walks: false, legCount: 0)
let human = Creature(name: "Human", swims: true, flies: false, walks: true, legCount: 2)
let penguin = Creature(name: "Penguin", swims: true, flies: false, walks: true, legCount: 2)
let swift = Creature(name: "Swift", swims: false, flies: true, walks: true, legCount: 2)
let creaturesArray = [ant, ant, ant, bumbleBee, cat, flyingFish, human, penguin, swift]
let swimmers = Set(creaturesArray.filter({ $0.swims }))
let walkers = Set(creaturesArray.filter({ $0.walks }))
let fliers = Set(creaturesArray.filter({ $0.flies }))
let flyingWalkers = fliers.intersect(walkers)
…being a Set, although there were three little ants in the source array, there’s only one in the set.
let walkingNonSwimmersNonFliers = walkers.subtract(swimmers).subtract(fliers)
let fliersAndSwimmers = fliers.union(swimmers)
Again, although the flying fish can do both, because we’re dealing with sets, it only appears once.





.jpeg)



