Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reduce array to set in Swift

I am trying to reduce an array of objects to a set in Swift and this is my code:

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

However, I get an error:

Type of expression is ambiguous without more context. 

I do not understand what the problem is, since the type of URL is definitely String. Any ideas?

like image 539
Banana Avatar asked Dec 08 '15 17:12

Banana


People also ask

How do I convert an array to a 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 }) .

What is array reduce in Swift?

Swift version: 5.6. The reduce() method iterates over all items in array, combining them together somehow until you end up with a single value.

What is Compactmap in Swift?

Returns an array containing the non- nil results of calling the given transformation with each element of this sequence.


2 Answers

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 }).

like image 60
NRitH Avatar answered Sep 17 '22 18:09

NRitH


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" 
like image 28
Imanou Petit Avatar answered Sep 20 '22 18:09

Imanou Petit