Reduce array to set in Swift Reduce array to set in Swift arrays arrays

Reduce array to set in Swift


You don't have to reduce an array to get it into a set; just create the set with an array: let objectSet = Set(objects.map { $0.URL }).


With Swift 5.1, you can use one of the three following examples in order to solve your problem.


#1. Using Array's map(_:) method and Set's init(_:) initializer

In the simplest case, you can map you initial array to an array of urls (String) then create a set from that array. The Playground below code shows how to do it:

struct MyObject {    let url: String}let objectArray = [    MyObject(url: "mozilla.org"),    MyObject(url: "gnu.org"),    MyObject(url: "git-scm.com")]let urlArray = objectArray.map({ $0.url })let urlSet = Set(urlArray)dump(urlSet)// ▿ 3 members//   - "git-scm.com"//   - "mozilla.org"//   - "gnu.org"

#2. Using Array's reduce(into:_:) method

struct MyObject {    let url: String}let objectArray = [    MyObject(url: "mozilla.org"),    MyObject(url: "gnu.org"),    MyObject(url: "git-scm.com")]let urlSet = objectArray.reduce(into: Set<String>(), { (urls, object) in    urls.insert(object.url)})dump(urlSet)// ▿ 3 members//   - "git-scm.com"//   - "mozilla.org"//   - "gnu.org"

As an alternative, you can use Array's reduce(_:_:) method:

struct MyObject {    let url: String}let objectArray = [    MyObject(url: "mozilla.org"),    MyObject(url: "gnu.org"),    MyObject(url: "git-scm.com")]let urlSet = objectArray.reduce(Set<String>(), { (partialSet, object) in    var urls = partialSet    urls.insert(object.url)    return urls})dump(urlSet)// ▿ 3 members//   - "git-scm.com"//   - "mozilla.org"//   - "gnu.org"

#3. Using an Array extension

If necessary, you can create a mapToSet method for Array that takes a transform closure parameter and returns a Set. The Playground below code shows how to use it:

extension Array {    func mapToSet<T: Hashable>(_ transform: (Element) -> T) -> Set<T> {        var result = Set<T>()        for item in self {            result.insert(transform(item))        }        return result    }}struct MyObject {    let url: String}let objectArray = [    MyObject(url: "mozilla.org"),    MyObject(url: "gnu.org"),    MyObject(url: "git-scm.com")]let urlSet = objectArray.mapToSet({ $0.url })dump(urlSet)// ▿ 3 members//   - "git-scm.com"//   - "mozilla.org"//   - "gnu.org"


reduce() method expects a closure that returns a combined value, while insert() methods of Set value does not return anything but instead it inserts a new element into the existing set.

In order to make it work you would need to do something like:

objects.reduce(Set<String>()) {    $0.union(CollectionOfOne($1.URL))}

But the above is a bit of an unnecessary complication. If you have a big array, that would mean quite a number of ever-growing sets to be created while Swift goes over all the elements from objects. Better follow the advice from @NRitH and use map() as that would make a resulting set in one go.