261

An NSSet can be converted to Array using set.allObjects() but there is no such method in the new Set (introduced with Swift 1.2). It can still be done by converting Swift Set to NSSet and use the allObjects() method but that is not optimal.

6 Answers 6

478

You can create an array with all elements from a given Swift Set simply with

let array = Array(someSet)

This works because Set conforms to the SequenceType protocol and an Array can be initialized with a sequence. Example:

let mySet = Set(["a", "b", "a"])  // Set<String>
let myArray = Array(mySet)        // Array<String>
print(myArray) // [b, a]
Sign up to request clarification or add additional context in comments.

7 Comments

As a side note, let array = Array(someSet) also works in Swift 2
... or let myArray = myNSSet.allObjects as! [mySpecificType]
@plusangel: Yes, if an NSSet is given. The question was about a Swift Set.
@KendallHelmstetterGelner: I have double-checked the above code example with both Swift 2.3 and Swift 3. It compiled and worked as expected for me. What error do you get?
@MartinR Interesting, I was trying it with a set from an NSManagedObject relationship, and it did not like the Array constructor at the time - now that I try to reproduce the problem though, I cannot. I do have to add the "arrayLiteral:" label into the Array constructor though. I removed my previous comment so it doesn't confuse anyone, thanks for checking! I don't know why the Swift guide does not have this conversion form...
|
26

In the simplest case, with Swift 3, you can use Array's init(_:) initializer to get an Array from a Set. init(_:) has the following declaration:

init<S>(_ s: S) where S : Sequence, Element == S.Iterator.Element

Creates an array containing the elements of a sequence.

Usage:

let stringSet = Set(arrayLiteral: "car", "boat", "car", "bike", "toy")    
let stringArray = Array(stringSet)

print(stringArray)
// may print ["toy", "car", "bike", "boat"]

However, if you also want to perform some operations on each element of your Set while transforming it into an Array, you can use map, flatMap, sort, filter and other functional methods provided by Collection protocol:

let stringSet = Set(["car", "boat", "bike", "toy"])
let stringArray = stringSet.sorted()

print(stringArray)
// will print ["bike", "boat", "car", "toy"]
let stringSet = Set(arrayLiteral: "car", "boat", "car", "bike", "toy") 
let stringArray = stringSet.filter { $0.characters.first != "b" }

print(stringArray)
// may print ["car", "toy"]
let intSet = Set([1, 3, 5, 2]) 
let stringArray = intSet.flatMap { String($0) }

print(stringArray)
// may print ["5", "2", "3", "1"]
let intSet = Set([1, 3, 5, 2])
// alternative to `let intArray = Array(intSet)`
let intArray = intSet.map { $0 }

print(intArray)
// may print [5, 2, 3, 1]

1 Comment

Using one of this methods I can make optional array from optional set.
26

I created a simple extension that gives you an unsorted Array as a property of Set in Swift 4.0.

extension Set {
    var array: [Element] {
        return Array(self)
    }
}

If you want a sorted array, you can either add an additional computed property, or modify the existing one to suit your needs.

To use this, just call

let array = set.array

1 Comment

If the extension in a framework, you need to add public keyword
14

ADDITION :

Swift has no DEFINED ORDER for Set and Dictionary.For that reason you should use sorted() method to prevent from getting unexpected results such as your array can be like ["a","b"] or ["b","a"] and you do not want this.

TO FIX THIS:

FOR SETS

var example:Set = ["a","b","c"]
let makeExampleArray = [example.sorted()]
makeExampleArray 

Result: ["a","b","c"]

Without sorted()

It can be:

["a","b","c"] or ["b","c","a",] or ["c","a","b"] or ["a","c","b"] or ["b","a","c"] or ["c","b","a"] 

simple math : 3! = 6

Comments

6

The current answer for Swift 2.x and higher (from the Swift Programming Language guide on Collection Types) seems to be to either iterate over the Set entries like so:

for item in myItemSet {
   ...
}

Or, to use the "sorted" method:

let itemsArray = myItemSet.sorted()

It seems the Swift designers did not like allObjects as an access mechanism because Sets aren't really ordered, so they wanted to make sure you didn't get out an array without an explicit ordering applied.

If you don't want the overhead of sorting and don't care about the order, I usually use the map or flatMap methods which should be a bit quicker to extract an array:

let itemsArray = myItemSet.map { $0 }

Which will build an array of the type the Set holds, if you need it to be an array of a specific type (say, entitles from a set of managed object relations that are not declared as a typed set) you can do something like:

var itemsArray : [MyObjectType] = []
if let typedSet = myItemSet as? Set<MyObjectType> {
 itemsArray = typedSet.map { $0 }
}

1 Comment

myItemSet.sorted() requires that the elements are Comparable. – myItemSet.map { $0 } should produce the same result as Array(myItemSet), both create an array by enumerating all elements of the set. The latter still works for me, some details on your above comment would be appreciated.
-2

call this method and pass your set

func getArrayFromSet(set:NSSet)-> NSArray {

return set.map ({ String($0) })
}

Like This :

var letters:Set = Set<String>(arrayLiteral: "test","test") // your set
print(self.getArrayFromSet(letters))

1 Comment

Use Array(<Set>) is a better choice

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.