212

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.

Martin R
  • 488,667
  • 78
  • 1,132
  • 1,248
Fried Rice
  • 2,929
  • 3
  • 16
  • 21

6 Answers6

400

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]
Martin R
  • 488,667
  • 78
  • 1,132
  • 1,248
  • 4
    As a side note, `let array = Array(someSet)` also works in Swift 2 – Suragch Jul 23 '15 at 05:07
  • ... or let myArray = myNSSet.allObjects as! [mySpecificType] – angelos.p Dec 13 '15 at 11:17
  • 3
    @plusangel: Yes, if an `NSSet` is given. The question was about a Swift `Set`. – Martin R Dec 13 '15 at 11:25
  • @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? – Martin R Oct 25 '16 at 05:19
  • @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... – Kendall Helmstetter Gelner Oct 26 '16 at 03:52
22

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]
Imanou Petit
  • 76,586
  • 23
  • 234
  • 201
12

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

11

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
CodeBender
  • 30,010
  • 12
  • 103
  • 113
3

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 }
}
Kendall Helmstetter Gelner
  • 73,251
  • 26
  • 123
  • 148
  • `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. – Martin R Oct 25 '16 at 19:03
-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))
Shubham bairagi
  • 913
  • 7
  • 25